Итак, у меня есть простой 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());
}
};
это гарантирует, что он имеет неконстантный T
и гарантирует, что это unique
когда это .write([&](T&){})
с этим.
C ++ 17 обесценивание .unique()
кажется, указывает на то, что этот дизайн имеет недостатки.
Я предполагаю, что если мы начнем с cow_ptr<int> ptr
с 1
в потоке A, передать его в поток B, сделать его уникальным, изменить его на 2
, проходить ptr
это назад и читать это в потоке A
мы создали условия гонки.
Как это исправить? Могу ли я просто добавить барьер памяти в write
? Который из? Или проблема более фундаментальная?
Менее вероятны симптомы на x86 из-за того, что согласованность памяти x86 выходит за рамки требований C ++?
Я думаю, что идея осудить это состоит в том, что он не может быть использован неправильно, как если бы у вас был такой код:
if(sp.unique()) {
// some deinitialisation
} else {
// somebody else will deinitialise.
}
Вполне возможно, что он не сможет деинициализироваться, если он будет выполняться 2 раза одновременно.
В вашем конкретном случае я не вижу проблем, потому что
Я не думаю, что есть какие-либо другие проблемы с заказами на доступ к памяти, так как счетчики в shared_ptr
являются атомными.
Я бы, наверное, просто переключился на use_count == 1
может быть с соответствующим комментарием
Других решений пока нет …