2017-10-12 53 views
6

所以我有一个简单的cow_ptr。它看起来是这样的:使用shared_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&){}) s到它。

弃用.unique()似乎表明此设计存在缺陷。

我猜测,如果我们开始与在线程A 1一个cow_ptr<int> ptr,它传递给线程B,使其具有唯一性,其修改为2,通过ptr回读它的线程A,我们已经产生了种族条件。

我该如何解决这个问题?我可以简单地在write中添加内存障碍吗?哪一个?还是这个问题更根本?

由于x86内存一致性超出了C++的要求,x86上的症状可能性较低吗?

回答

0

我想弃用此的想法是,它不能被使用不当一样,如果你有这样的代码:

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

这是可能的,它会失败deinitialise如果它发生运行同时2次。

在我看不出有什么问题,你的具体情况,因为

  1. ,如果它不是唯一的,并成为独特的 - 这没什么大不了的,你只会让额外的复制
  2. ,如果它是独一无二的,变得不是唯一的,那么你改变并复制在两个不同的线程相同的实例(这将是反正有问题)

我不认为有任何其他问题,用命令来访问内存,因为柜台shared_ptr被原子。

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