有没有办法挂钩 std 容器的插入和删除操作?
Is there any way to hook insertion and deletion operations for the std containers?
比方说,我们要对 std::map
进行子类化,我们需要捕获容器中的所有插入和删除操作 to/from。例如,为了保存有关容器中存在的密钥的一些特定于应用程序的信息。
如果可能的话,最简单的方法是什么?
可能,最明显的方法是覆盖执行插入和删除的所有方法和运算符。但我想,这样一来,很容易漏掉一些东西,不是吗?
一般情况下没有办法做到这一点。继承不是一个好主意,因为 std::map
不是多态的,并且当您使用指向映射的指针时不会发生虚拟分派。你不妨在这一点上使用一个简单的包装器 class 并为自己省去很多麻烦:
#include <iostream>
#include <map>
template <class Key, class Value>
struct Map {
private:
std::map<Key, Value> _data;
public:
template <class Y, class T>
void insert(Y &&key, T &&val) {
std::cout << "[" << key << "] = " << val << "\n";
_data.insert_or_assign(std::forward<Y>(key), std::forward<T>(val));
}
void remove(Key const &key) {
auto const it = _data.find(key);
if (it == _data.end())
return;
std::cout << "[" << key << "] -> removed\n";
_data.erase(it);
}
Value *get(Key const &key) {
auto const it = _data.find(key);
if (it == _data.end())
return nullptr;
return &it->second;
}
};
int main() {
Map<int, char const *> map;
map.insert(10, "hello");
map.insert(1, "world");
map.remove(1);
map.remove(10);
map.remove(999);
}
简答:否
C++ 标准库数据结构并非旨在支持此用例。您可以 subclass 并尝试覆盖,但这不会像您期望的那样工作。事实上,如果您在关键字 override
的帮助下正确执行此操作,您将在编译时遇到错误。问题是 std::map
方法不是 virtual
,所以它们不支持所谓的 后期绑定 。使用指向 std::map
的引用和指针的函数将继续使用 std::map
方法,即使在传递 std::map
subclass.
实例的情况下也是如此
您唯一的选择是创建一个全新的 class your_map
,其中包含 std::map
的所需方法的子集,并将作业委托给 std::map
的内部实例] 如 Ayxan Haqverdili 的回答所示。不幸的是,此解决方案要求您更改使用代码的函数签名,将 std::map &
参数替换为 your_map &
,这可能并非总是可行。
比方说,我们要对 std::map
进行子类化,我们需要捕获容器中的所有插入和删除操作 to/from。例如,为了保存有关容器中存在的密钥的一些特定于应用程序的信息。
如果可能的话,最简单的方法是什么?
可能,最明显的方法是覆盖执行插入和删除的所有方法和运算符。但我想,这样一来,很容易漏掉一些东西,不是吗?
一般情况下没有办法做到这一点。继承不是一个好主意,因为 std::map
不是多态的,并且当您使用指向映射的指针时不会发生虚拟分派。你不妨在这一点上使用一个简单的包装器 class 并为自己省去很多麻烦:
#include <iostream>
#include <map>
template <class Key, class Value>
struct Map {
private:
std::map<Key, Value> _data;
public:
template <class Y, class T>
void insert(Y &&key, T &&val) {
std::cout << "[" << key << "] = " << val << "\n";
_data.insert_or_assign(std::forward<Y>(key), std::forward<T>(val));
}
void remove(Key const &key) {
auto const it = _data.find(key);
if (it == _data.end())
return;
std::cout << "[" << key << "] -> removed\n";
_data.erase(it);
}
Value *get(Key const &key) {
auto const it = _data.find(key);
if (it == _data.end())
return nullptr;
return &it->second;
}
};
int main() {
Map<int, char const *> map;
map.insert(10, "hello");
map.insert(1, "world");
map.remove(1);
map.remove(10);
map.remove(999);
}
简答:否
C++ 标准库数据结构并非旨在支持此用例。您可以 subclass 并尝试覆盖,但这不会像您期望的那样工作。事实上,如果您在关键字 override
的帮助下正确执行此操作,您将在编译时遇到错误。问题是 std::map
方法不是 virtual
,所以它们不支持所谓的 后期绑定 。使用指向 std::map
的引用和指针的函数将继续使用 std::map
方法,即使在传递 std::map
subclass.
您唯一的选择是创建一个全新的 class your_map
,其中包含 std::map
的所需方法的子集,并将作业委托给 std::map
的内部实例] 如 Ayxan Haqverdili 的回答所示。不幸的是,此解决方案要求您更改使用代码的函数签名,将 std::map &
参数替换为 your_map &
,这可能并非总是可行。