So habe ich eine einfache cow_ptr
. Es sieht etwa so aus:Kopieren am Schreiben mit 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());
}
};
dies garantiert, dass es einen nicht-const T
hält und sichert es unique
ist, wenn es .write([&](T&){})
s zu.
Die c++17 Abwertung von .unique()
scheint darauf hinzuweisen, dass dieses Design fehlerhaft ist.
Ich vermute, dass, wenn wir mit einem cow_ptr<int> ptr
mit 1
in Thread A zu starten, geben sie B einzufädeln, es einzigartig machen, ändern Sie es zu 2
, es ptr
zurück und haben passieren lesen es in thread A
wir ein Rennen erzeugt Bedingung.
Wie behebe ich das? Kann ich einfach eine Speicherbarriere in write
hinzufügen? Welcher? Oder ist das Problem grundlegender?
Sind die Symptome auf x86 aufgrund der x86-Speicherkonsistenz, die über C++ hinausgeht, weniger wahrscheinlich?