私はこのパターンに従うクラスを持っています:
class Foo
{
public:
// Create a Foo whose value is absolute
Foo(int x) : other_(0), a_(x) {}
// Create a Foo whose value is relative to another Foo
Foo(Foo * other, int dx) : other_(other), a_(dx) {}
// Get the value
double x() const
{
if(other_)
return other_->x() + a_;
else
return a_;
}
private:
Foo * other_;
int a_;
};
Foo
オブジェクトはすべて によって所有されていますBar
:
class Bar
{
public:
~Bar() { for(int i=0; i<foos_.size(); i++) delete foos_[i]; }
private:
vector<Foo*> foos_;
};
もちろん、これはアイデアを得るための単純化された例です。Foo
s のループがないこと、およびリンクされFoo
た s がすべて の同じインスタンスに属していることを保証しますBar
。ここまでは順調ですね。C++11 のやり方で物事を行うには、 in を使用vector< unique_ptr<Foo> > foos_;
し、コンストラクターの潜在的な引数としてBar
渡します。foos_[i].get()
Foo
契約があります:
これは GUI アプリケーションであり、ユーザーはインタラクティブに一部Foo
を自由に削除できます。予想される動作は、foo1
が削除され、foo2
に対して相対的である場合、 「絶対」foo1
になることです。foo2
void Foo::convertToAbsolute() { a_ += other_->x(); other_ = 0; }
void usageScenario()
{
Foo * foo1 = new Foo(42);
Foo * foo2 = new Foo(foo1, 42);
// Here, foo1->x() = 42 and foo2->x() = 84
foo1->setX(10);
// Here, foo1->x() = 10 and foo2->x() = 52
delete foo1;
// Here, foo2->x() = 52
}
バックポインターを含む DAG 構造を使用することにより、生のポインターを使用してそれを行うことができることを知っているので、Foo
誰が「それらに依存している」かを認識し、削除する前にそれらを通知できます (可能な解決策については、こちらとこちらで詳しく説明しています)。
私の質問は次のとおりです。同じように処理しますか? 標準の C++11 スマート ポインターを使用して、明示的なバックポインターを回避areRelativeToMe_[i]->convertToAbsolute();
し、デストラクタで明示的に呼び出すことを回避する方法はありFoo
ますか? 私は次のようなことを考えてweak_ptr
いました:
class Foo { /* ... */ weak_ptr<Foo> other_; };
double Foo::x() const
{
if(other_.isExpired())
convertToAbsolute();
// ...
}
しかし、問題はconvertToAbsolute()
、相対Foo
がまだ存在する必要があることです。したがって、「この参照は論理的に期限切れです」と伝えることができる非所有のスマートポインターが必要ですが、実際には、参照されたオブジェクトが不要になるまで、その有効期間を延長します。
weak_ptr
他のものと共有されなくなるまで、有効期間を延長するように見える可能性がありますweak_ptr
。
class Foo { /* ... */ extended_weak_ptr<Foo> other_; };
double Foo::x() const
{
if(other_.isExpired())
{
convertToAbsolute();
other_.reset(); // now the object is destructed, unless other
// foos still have to release it
}
// ...
}
またはshared_ptr
、所有権のレベルが異なる のように:
class Bar { /* ... */ vector< multilevel_shared_ptr<Foo> foos_; };
class Foo { /* ... */ multilevel_shared_ptr<Foo> other_; };
void Bar::createFoos()
{
// Bar owns the Foo* with the highest level of ownership "Level1"
// Creating an absolute Foo
foos_.push_back( multilevel_unique_ptr<Foo>(new Foo(42), Level1) );
// Creating a relative Foo
foos_.push_back( multilevel_unique_ptr<Foo>(new Foo(foos_[0],7), Level1) );
}
Foo::Foo(const multilevel_unique_ptr<Foo> & other, int dx) :
other_( other, Level2 ),
// Foo owns the Foo* with the lowest level of ownership "Level2"
a_(dx)
{
}
double Foo::x() const
{
if(other_.noLevel1Owner()) // returns true if not shared
// with any Level1 owner
{
convertToAbsolute();
other_.reset(); // now the object is destructed, unless
// shared with other Level2 owners
}
// ...
}
何かご意見は?