Tak więc mam prosty cow_ptr
. Wygląda to mniej więcej tak:Kopiuj przy użyciu funkcji udostępnionej
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());
}
};
to gwarantuje, że posiada const T
i zapewnia, że jest unique
gdy .write([&](T&){})
s do niego.
Wycofanie c++17 z .unique()
wydaje się wskazywać, że ten projekt jest wadliwy.
Jestem zgadywania, że jeśli zaczniemy z cow_ptr<int> ptr
z 1
w wątku A, przekazać go do wątku B, uczynić go wyjątkowym, modyfikować je 2
przechodzą ptr
go z powrotem i przeczytaj ją w wątku A
mamy generowane wyścig stan.
Jak to naprawić? Czy mogę po prostu dodać barierę pamięci w numerze write
? Który? A może problem jest bardziej fundamentalny?
Czy objawy są mniej prawdopodobne na x86 z powodu spójności pamięci x86 wykraczającej poza wymagania C++?