我有一个遵循这种模式的课程:
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
对象都归 a 拥有Bar
:
class Bar
{
public:
~Bar() { for(int i=0; i<foos_.size(); i++) delete foos_[i]; }
private:
vector<Foo*> foos_;
};
当然,这是一个简单的例子来理解这个想法。我保证没有 s 的循环Foo
,并且链接Foo
的 s 都属于 的同一个实例Bar
。到目前为止,一切都很好。要以 C++11 的方式做事,我会使用vector< unique_ptr<Foo> > foos_;
in ,并作为构造函数的潜在参数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
}
// ...
}
有什么想法吗?