有没有办法挂钩 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 &,这可能并非总是可行。