使用shared_ptr复制写入

时间:2017-10-12 02:35:58

标签: c++ c++17 memory-barriers copy-on-write

所以我有一个简单的cow_ptr。它看起来像这样:

template<class T, class Base=std::shared_ptr<T const>>
struct cow_ptr:private Base{
  using Base::operator*;
  using Base::operator->;
  using Base::operator bool;
  // etc

  cow_ptr(std::shared_ptr<T> ptr):Base(ptr){}

  // defaulted special member functions

  template<class F>
  decltype(auto) write(F&& f){
    if (!unique()) self_clone();
    Assert(unique());
    return std::forward<F>(f)(const_cast<T&>(**this));
  }
private:
  void self_clone(){
    if (!*this) return;
    *this = std::make_shared<T>(**this);
    Assert(unique());
  }
};

这可以保证它包含非const T并确保unique.write([&](T&){})

.unique()的{​​{3}}弃用似乎表明此设计存在缺陷。

我猜测如果我们从线程A中的cow_ptr<int> ptr 1开始,将其传递给线程B,使其唯一,将其修改为2,传递{{1它返回并在线程ptr中读取它我们已经生成了竞争条件。

我该如何解决这个问题?我可以在A中添加内存屏障吗?哪一个?或问题更为根本?

由于x86内存的一致性超出了C ++的要求,x86上的症状是否会降低?

1 个答案:

答案 0 :(得分:0)

我认为弃用此功能的想法是不能错误地使用它,就像你有这样的代码一样:

if(sp.unique()) { 
    // some deinitialisation
} else {
    // somebody else will deinitialise.
}

如果碰巧同时运行2次,它可能无法取消初始化。

在您的特定情况下,我认为没有问题,因为

  1. 如果它不是唯一的并且变得独一无二 - 这没什么大不了的,你只需要制作额外的副本
  2. 如果它是唯一的并且变得不唯一,那么你在两个不同的线程中更改和复制相同的实例(无论如何这将是一个问题)
  3. 我认为订单访问内存没有任何其他问题,因为shared_ptr中的计数器是原子的。

    我可能只是切换到use_count == 1可能会有适当的评论

相关问题