简体   繁体   English

如何使用存储在c ++中的std向量中的std :: list迭代器制作一个复制安全容器?

[英]How to make a copy safe container with std::list iterators stored in a std vector in c++?

For my GUI i need a class with the following purposes to manage controls (windows, buttons etc) 对于我的GUI,我需要一个具有以下目的的类来管理控件(窗口,按钮等)

  • random access to the elements by [index] 通过[index]随机访问元素
  • random access to the elements by ["key"] 通过["key"]随机访问元素
  • pointer stability, so ptr=&container[index] wont change if elements are added or erased 指针稳定性,所以如果添加或删除元素, ptr=&container[index]不会改变
  • copy safety. 复制安全。 All elements must by stored in the container and copied if '=' is used like container2=conatiner1 (deep-copy) 所有元素必须存储在容器中并复制,如果使用'='就像container2=conatiner1 (深拷贝)
  • the order of the elements in the list must be changeable, yet the pointers to the elements must remain valid. 列表中元素的顺序必须是可更改的,但指向元素的指针必须保持有效。 If ptr1=container[1] and ptr2=container[2] , then after swapping the order of 1 and 2, ptr1==container[2] and ptr2==container[1] 如果ptr1=container[1]ptr2=container[2] ,那么在交换1和2的顺序之后, ptr1==container[2]ptr2==container[1]

I came to the conclusion that std::list provides the stability for the pointers that I need and std::vector the random access. 我得出结论,std :: list为我需要的指针和std :: vector提供了随机访问的稳定性。 So I have the idea to store a tuple of std string and iterator in a vector. 所以我有想法在向量中存储std字符串和迭代器的元组。 However, the iterators are all invalid after the container is copied. 但是,复制容器后迭代器都无效。

Any suggestions on how to tackle this problem best? 关于如何最好地解决这个问题的任何建议?

Here the main code of the current approach (only important parts are included): 这里是当前方法的主要代码(仅包括重要部分):

template < class T >
class ControlList 
{
    struct Tuple{std::string first;typename std::list<T>::iterator second;};
    std::vector<Tuple> list;
    std::list<T> objects;

    inline T& operator [](int i)
    {
        return *list[i].second;
    }
    inline T& operator [](std::string s)
    {
        loopi(0,vlist.size()) 
        if(s==vlist[i].first) 
            return *vlist[i].second;
    }
}

The string access is slow, but usually the container has not more than 10 elements and its used rarely in the program. 字符串访问速度很慢,但通常容器的元素不超过10个,并且在程序中很少使用它。

Update: 更新:

The shared pointer is already good, but cannot solve for the deep copy I need. 共享指针已经很好了,但无法解决我需要的深拷贝。 Lets say I have window2=window1. 可以说我有window2 = window1。 Now if I have a shared pointer, then pushing a button in window2 also pushes the same button in window1, which is not wanted. 现在,如果我有一个共享指针,那么按下window2中的按钮也会在window1中按下相同的按钮,这是不需要的。 I really need a new instance of all objects contained in the container. 我真的需要容器中包含的所有对象的新实例。

Is it possible to override the copy constructor to create new instances of the objects referenced by the smart pointers ? 是否可以覆盖复制构造函数来创建智能指针引用的对象的新实例?

Both, windows and buttons are stored in a ControlList , where a window contains multiple lists. 窗口和按钮都存储在ControlList ,其中窗口包含多个列表。

Update2: UPDATE2:

Overriding the copy constructor and the assignment constructor has apparently solved the problem 覆盖复制构造函数和赋值构造函数显然已经解决了这个问题

Update3: UPDATE3:

I just released the GUI this class was intended for under MIT. 我刚刚发布了这个课程用于麻省理工学院的GUI。

Download here. 在这里下载。

If you were to use std::vector<std::pair<std::string, std::unique_ptr<T>>> , you could copy the items however you wanted to, and the resulting value would just require one more step of indirection to access. 如果你要使用std::vector<std::pair<std::string, std::unique_ptr<T>>> ,你可以复制你想要的项目,结果值只需要一个步骤间接访问。 This would eliminate much of the complexity you have right now with 3 different structures. 这将消除您现在拥有3种不同结构的大部分复杂性。 As a bonus, the items would also automatically cleanup after itself. 作为奖励,这些物品也会自动清理。

If you require owner-observer semantics with the pointers, you could instead opt for std::shared_ptr<T> and std::weak_ptr<T> . 如果你需要使用指针的所有者 - 观察者语义,你可以改为选择std::shared_ptr<T>std::weak_ptr<T> Shared pointers can easily create weak pointers, which act as non-owning observers which do not affect the referencing counting of the shared pointer. 共享指针可以轻松创建弱指针,这些指针充当非拥有的观察者,不会影响共享指针的引用计数。

Edit: Just to add on, shared_ptr and the other smart pointers are C++11 and later-exlcusive. 编辑:只需添加, shared_ptr和其他智能指针是C ++ 11及更高版本 - exlcusive。 If you desire C++03-compatible solutions, you can look to past Boost implementations or perhaps create one yourself by observing the C++11/14 spec. 如果您需要与C ++ 03兼容的解决方案,您可以查看过去的Boost实现,或者通过观察C ++ 11/14规范自己创建一个。

Edit2: Here is some code to assist: Edit2:这是一些协助的代码:

http://coliru.stacked-crooked.com/a/a9bf52e5428a48af http://coliru.stacked-crooked.com/a/a9bf52e5428a48af

#include <vector>  //vector
#include <memory>  //smart pointers
#include <utility> //pair
#include <string>  //string
#include <iostream>//cout

template <class T>
class Container {
public:
    inline void push(const std::string& s, const T& t) {
        objects.push_back(std::pair<std::string, std::shared_ptr<T>>(s, std::make_shared<T>(t)));   
    }

    inline T& operator [](const size_t& i)
    {
        return *(objects[i]->second);
    }
    inline T& operator [](const std::string& s)
    {
        for (auto it : objects) {
            if(s == it.first) { 
                return *(it.second);
            }
        }

        //welp, what do you do here if you can't find it?
    }
private:
    std::vector<std::pair<std::string, std::shared_ptr<T>>> objects;
};

int main() {
    Container<int> cont;
    std::string str {"hi"};
    int i {2};

    cont.push(str, i);

    //This is good...
    std::cout << cont["hi"] << std::endl;

    //But undefined behavior!
    std::cout << cont["02"] << std::endl;
    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM