使用shared_ptr复制写入

Yak*_*ont 8 c++ copy-on-write memory-barriers c++17

所以我有一个简单的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());
  }
};
Run Code Online (Sandbox Code Playgroud)

这可以保证它拥有一个非常量T并确保它在unique何时出现.write([&](T&){}).

的折旧.unique()似乎表明这种设计是有缺陷的.

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

我该如何解决?我可以简单地添加内存屏障write吗?哪一个?或者问题更根本?

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

Ria*_*iaD 0

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

if(sp.unique()) { 
    // some deinitialisation
} else {
    // somebody else will deinitialise.
}
Run Code Online (Sandbox Code Playgroud)

如果同时运行两次,则可能无法取消初始化。

在你的具体情况下,我认为没有问题,因为

  1. 如果它不是独一无二的并且变得独一无二 - 没什么大不了的,你只需制作额外的副本
  2. 如果它是唯一的并且变得不唯一,那么您将在两个不同的线程中更改和复制同一实例(无论如何这都会成为问题)

我认为访问内存的命令不存在任何其他问题,因为计数器shared_ptr是原子的。

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