从const c ++ - vector中检索非const元素

时间:2014-10-03 10:56:02

标签: c++ vector const

在我的程序中,我有全局数据。

每个程序模块都必须具有对数据的读写权限。截至目前,我不使用线程,而是使用Qt的信号和插槽,因此 - 虽然我还没有遇到崩溃 - 但我认为我在某些时候需要同步。

因此,每个模块都保存这样的数据:

const std::vector<T>& data;

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

==&GT;这意味着可以安全地从任何地方读取和添加/删除数据。

我遇到的问题是修改数据。 T的制定者知道竞争条件。使用data,我想允许调用data.at(3).setAttr("hello"),但对于常量向量,at()只返回常量引用。为什么以及如何使其发挥作用?我可以抛弃常数,但这感觉不对。

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

3 个答案:

答案 0 :(得分:2)

此场景正是您想要将constness转换为的地方。您已经仔细设计了系统以使其正常工作,因此当您完全准备好它并且正确时,不要感到严重关于丢弃const要做。

答案 1 :(得分:2)

  1. 同步写入使得未读取的读取可能/也将损坏内存。
  2. 逐渐消除气味。
  3. 低开销解决方案(虽然没有很好地封装)如下所示。想法在@ JonathanWakely的评论中得到了很好的总结:“添加一个带有仿函数并将其应用于非const向量的全局函数”

    header.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_);
        }
    }
    

    如果矢量的内容不经常变化,那么你可以使用copy_ on-write和shared_ptr将争用保持在最低限度。

答案 2 :(得分:2)

既然你提出了建议

  1. 你可以用一个大致相同的类来包装vector。这也可以摆脱你提到的全局功能,这很好。如果您希望班级的实例为const,请在内部使用mutable向量。
  2. const_cast,但尝试将其隐藏在函数中的某个位置。
  3. 存储智能指针。我希望我没错(这已经有一段时间了),但我认为你可以通过const智能指针检索一个非const元素。
  4. 详细说明(1)因为我在评论中被要求:

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

    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;
    }
    
相关问题