C++ 从常量c+中检索非常量元素+-矢量

C++ 从常量c+中检索非常量元素+-矢量,c++,vector,constants,C++,Vector,Constants,在我的程序中,我有全球数据 每个程序模块必须具有对数据的读写访问权限。到目前为止,我不使用线程,但使用Qt的信号和插槽,因此-尽管我还没有遇到崩溃-我想我需要在某个时候进行同步 因此,每个模块都保存以下数据: const std::vector<T>& data; const std::vector&data; 其中T是一个自定义类。因此,每个模块都可以读取数据。为了保持一致性,向量本身是常量,以禁止并发删除或删除。这些都是使用全局函数(如addToData(T elem

在我的程序中,我有全球数据

每个程序模块必须具有对数据的读写访问权限。到目前为止,我不使用线程,但使用Qt的信号和插槽,因此-尽管我还没有遇到崩溃-我想我需要在某个时候进行同步

因此,每个模块都保存以下数据:

const std::vector<T>& data;
const std::vector&data;
其中T是一个自定义类。因此,每个模块都可以读取数据。为了保持一致性,
向量
本身是常量,以禁止并发删除或删除。这些都是使用全局函数(如
addToData(T elem)
removeFromData(int id)
)完成的,这些函数可以同步。请注意,向量本身被声明为通过引用共享,这样,上面一个全局函数中的更改将导致每个程序模块中的数据一致

==>这意味着可以以安全的方式从任何地方读取和添加/删除数据

我遇到的问题是修改数据。
T
的设定者知道比赛条件。使用
data
,我想允许像
data.at(3).setAttr(“hello”)
这样的调用,但是对于常量向量,at()只返回常量引用。我为什么以及如何使它工作?我可以摆脱这种状态,但那感觉不对


考虑到我的架构,我也愿意接受建议。

这个场景正是你想要抛弃康斯特内斯的地方。您已经仔细设计了系统,使其能够正常工作,因此,当您完全准备好使用它时,您不必为丢弃
const
而感到不快,因为这是正确的操作

  • 同步写入而不同步读取也可能会损坏内存
  • 把恒久不变的气味扔掉
  • 低开销工作解决方案(尽管封装不好)如下所示。@JonathanWakely的评论很好地概括了这个想法:“添加一个全局函数,该函数接受一个函子并将其应用于非常量向量”

    标题.h

    struct no_synchronization {
        struct mutex {}
        struct guard {
          guard(mutex&) {}
        };
    };
    
    struct serialized {
       typedef std::mutex mutex;
       typedef std::lock_guard<mutex> guard;
    };
    
    template <class T, class S = no_synchronization>
    class spaghetti {
        typedef typename S::mutex mutex;
        typedef typename S::guard guard;
    
        static mutex mutex_;
        static std::vector<T> vector_;
    
        template <class F>
        static void read_global_vec(F const& f) {
            guard lock(mutex_);
            std::vector<T> const& ref = vector_;
            f(ref);
        }
    
        template <class F>
        static void write_global_vec(F const& f) {
            guard lock(mutex_);
            f(vector_);
        }
    }
    
    struct无同步{
    结构互斥体{}
    结构防护{
    保护(互斥&){}
    };
    };
    结构序列化{
    typedef std::互斥体互斥体;
    typedef std::锁紧护罩;
    };
    模板
    意大利面{
    typedef typename S::mutex mutex;
    typedef typename S::警卫;
    静态互斥;
    静态std::矢量;
    模板
    静态无效读取\全局\向量(F常量和F){
    保护锁(互斥锁);
    std::vector const&ref=向量;
    f(参考文献);
    }
    模板
    静态无效写入\u全局\u向量(F常量和F){
    保护锁(互斥锁);
    f(向量_u2;);
    }
    }
    

    如果向量的内容不经常更改,那么您可以使用带有共享ptr的写时复制来将争用降至最低。

    因为您需要建议

  • 您可以使用工作原理基本相同的类包装
    vector
    。这也将消除您提到的全局函数,这是很好的。如果希望类的实例为
    常量
    ,请在内部使用
    可变
    向量
  • const\u cast
    ,但尝试将其隐藏在函数中的某个位置
  • 存储智能指针。我希望我没有错(已经有一段时间了),但我认为可以通过const智能指针检索非const元素
  • 详细说明(1),因为我在评论中被要求:

    你需要vector的功能,它非常适合你的需要。但是vector的接口对于您需要的东西来说是笨拙的。这是经常遇到的情况,包装器是默认的解决方案。包装器是一个新类,它的接口符合您的需要,但它的实现几乎只是将所有工作委托给另一个类。使用包装器的目的是使包装器对象更容易正确使用,更难错误使用。它可能看起来有点像这样(未测试,不会编译):

    AWRAP类演示
    {
    公众:
    MyCustomClass和GetByIndex(int i)常量//可以抛出
    {
    std::lock\u guard lock(\u mutex);
    返回存储[i];
    }
    大小\u t大小(整数i)常数
    {
    std::lock\u guard lock(\u mutex);
    返回_storage.size();
    }
    无效添加(MyCustomClass&addThis)
    {
    std::lock\u guard lock(\u mutex);
    _存储。推回(添加此项);
    }
    bool Remove(MyCustomClass&removeThis)
    {
    std::lock\u guard lock(\u mutex);
    自动it=_storage.find(删除此项);
    if(it==\u storage.end())
    返回false;
    _存储。擦除(它);
    }
    模板void ForEach(F const&F)const
    {
    std::lock\u guard lock(\u mutex);
    用于(自动和输入:存储)
    f(i);
    }
    私人:
    std::矢量存储;
    std::mutex\u mutex;
    }
    
    我建议您创建自己的类,该类封装了一个
    std::vector
    ,提供所需的同步访问。(并且不具有全局数据)如果修改只与其他修改同步,而不与读取同步,则存在一个数据竞争,即UB。你想要一个读写器锁,或者其他更安全的习惯用法。我猜你是在问如何绕过元素向量和元素向量之间的模糊线;C++并没有使这一点变得简单,不幸的是,当你不使用线程时,我对所有的并发修改和同步的引用有点困惑。似乎您需要防止的只是对向量的递归访问(即,修改向量会导致调用某个函数,该函数会再次尝试修改向量)。这是相关的,但并不完全相同,使用global
    addToData
    /
    removeFromData
    函数并不一定有帮助。@BoBTFish向量可能已经有了同步访问,我正在询问向量的元素(也可以是
    class AWrapperForDemonstration
    {
    public:
        MyCustomClass& GetByIndex(int i) const // can throw
        {
             std::lock_guard<std::mutex> lock(_mutex);
             return _storage[i];
        }
        size_t Size(int i) const
        {
             std::lock_guard<std::mutex> lock(_mutex);
             return _storage.size();
        }
        void Add(MyCustomClass& addThis)
        {
             std::lock_guard<std::mutex> lock(_mutex);
             _storage.push_back(addThis);
        }
        bool Remove(MyCustomClass& removeThis)
        {
             std::lock_guard<std::mutex> lock(_mutex);
             auto it =_storage.find(removeThis);
             if (it == _storage.end())
                 return false;
             _storage.erase(it);
        }
        template <F> void ForEach(F const& f) const
        {
            std::lock_guard<std::mutex> lock(_mutex);
            for (auto& i : _storage)
                f(i);
        }
    private:
        std::vector<MyCustomClass> _storage;
        std::mutex _mutex;
    }