首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从const c++向量中检索非const元素

从const c++向量中检索非const元素
EN

Stack Overflow用户
提问于 2014-10-03 10:56:01
回答 3查看 829关注 0票数 2

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

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

因此,每个模块保存的数据如下:

代码语言:javascript
复制
const std::vector<T>& data;

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

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

我遇到的问题是数据的修改。T的策划者们知道种族状况。使用data,我希望允许像data.at(3).setAttr("hello")这样的调用,但是对于常量向量,at()只返回常量引用。我怎么才能让它起作用?我可以抛开不变,但这感觉不对。

考虑到我的架构,我也愿意听取一些建议。

EN

回答 3

Stack Overflow用户

发布于 2014-10-03 11:00:20

这种情况正是您想要抛弃恒常的地方。您已经仔细地设计了您的系统以正确地工作,所以当您已经完全准备好了它并且它是正确的事情时,不要对抛弃const感到难过。

票数 2
EN

Stack Overflow用户

发布于 2014-10-03 11:05:16

  1. 同步写入离开读取不同步也可能/将损坏内存。
  2. 消除气味的坚定性。

下面是工作低开销的解决方案(虽然没有很好的封装)。一个@JonathanWakely的评论很好地总结了这个想法:“添加一个带函子的全局函数,并将它应用到非const向量中。”

header.h

代码语言:javascript
复制
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_);
    }
}

如果向量的内容很少发生变化,那么可以使用shared_ptr进行复制,以将争用降到最低。

票数 2
EN

Stack Overflow用户

发布于 2014-10-03 11:17:30

既然你问我建议

  1. 您可以用一个工作方式基本相同的类包装vector。这也将消除您提到的全局函数,这是很好的。如果您希望类的实例是const,那么在内部使用mutable向量。
  2. const_cast,但是尝试将其隐藏在函数中的某个地方。
  3. 存储智能指针。我希望我没有错(这已经有一段时间了),但我认为您可以通过const智能指针检索非const元素。

为了详细说明(1),因为我在评论中被要求:

您需要向量的功能,这是一个很好的匹配您的需要。但是矢量的接口对于你所需要的东西是笨拙的。这是一种经常遇到的情况,包装器是默认的解决方案。包装器是一个新的类,它的接口与您的需要相匹配,但是它的实现实际上只是将所有的工作委托给另一个类。使用包装器的目的是使包装器对象更容易正确使用,更难使用错误。它可能看起来有点像这样(没有测试,不会编译):

代码语言:javascript
复制
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;
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26177709

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档