如何扩展std库容器,以便在单个元素发生更改时得到通知

How to extend std library containers to get notified when individual elements are changed

本文关键字:元素 单个 通知 扩展 何扩展 std      更新时间:2023-10-16

我想扩展std库容器,以便在容器的任何状态发生更改时通知应用程序。例如,当一个新项目被添加到列表中时,我希望容器调用应用程序中具有特定信息的方法。我的要求是跟踪由于给定操作而更改的内存地址。例如,如果插入一个新元素导致修改列表内部的某个对象,我想知道该对象的起始地址以及对象的大小,这样我就可以大致知道内存的哪个区域发生了更改。

更新:看来我的问题不是那么清楚。我不想拦截获取值的调用。相反,我想要的是跟踪内存是如何因操作而改变的。例如,当一个新元素添加到二叉树中时,树中某个节点中的指针会更新为指向新添加的节点。当这种情况发生时,我想得到这个节点的地址以及node类的大小的通知,这样我就可以放心地说,start_address到start_address+sizeof(NodeType)范围内的内存addess已经更改。在自定义内存池+自定义分配器的帮助下,我可以使用这些信息进行增量状态转储。

我不喜欢您给出的将地址返回到列表中内部内存位置的示例。如果有不同的线程使用可能无效的迭代器,则锁定容器直到该任务完成。

另一个例子是,当容器分配更多存储时发出通知,这是可以的。这里有一个非常简单的例子。我只实现了push(),它在底层向量上调用push_back。你甚至不能访问你已经推送的数据,但这对你来说很容易添加。

template <class T>
class notifyvector {
    std::vector<T> _vector;
    size_t _capacity;
    static const size_t initial_capacity = 20;
public:
    notifyvector() : _capacity(initial_capacity) {
        _vector.reserve(initial_capacity);
    }
    void push(T value){
        _vector.push_back(value);
        if (_capacity < _vector.capacity()){
            // the vector has grown
            _capacity = _vector.capacity();
            do_notify(_capacity);
        }
    }
    void do_notify(size_t newcap){
        // all you
        std::cout << "the vector has grown to " << newcap << std::endl;
    }
};

练习的重点是演示一个包装器,该包装器在控制底层容器的所有输入和输出的类中提供您想要的通知类型。这允许它检测事件并发送您想要的任何通知。

您可能允许访问底层容器的const引用(只读),并在写访问中检测要通知的事件,写访问必须通过容器的函数。

开箱即用,标准容器并不像您所描述的那样提供通知。

作为一个例子;

template<
    class T,
    class Allocator = std::allocator<T>
> class vector;

容器本质上有两个扩展点——类型T和分配器Allocator。容器的内部,例如节点、内部指针、计数器等,不会公开用于自定义。

为了模仿您想要的钩子,您需要利用标准容器的这两个扩展点。如果它们被证明是不够的,那么您将需要构建自己的容器。

提供自定义分配器可以帮助获得对象(对于使用它们的容器,这包括内部节点对象)构造、销毁和分配、释放等的通知。给定示例用法,自定义分配器可能是所需的全部;这些操作通常对应于容器增长、对象创建和销毁等。分配器提供(在分配期间)和被提供(在构造和销毁期间),内存的地址被更改。

您也可以包装容器中正在使用的类型,以通知您其状态的更改,但这可能过于夸张,并且很难识别容器本身和容器客户端所做的更改。

此外,您可以包装容器以提供所需的钩子,然后将所需功能的其余部分存根到所需容器的私有成员(或基类)。您甚至可以将其模板化以支持多种容器类型。