我在写Bar课。Bar需要访问其他类Foo才有用。因此,Foo实例必须比使用它的Bar实例长寿。
我无法在两种编写方式之间做出选择。这是一个例子:
#include <iostream>
#include <memory>
using namespace std;
struct Foo {
Foo(int _x) : x_(_x) {}
~Foo() {}
int x_;
};
struct Bar1 {
Bar1(Foo& _foo) : foo_(_foo) {}
void print_foo() {cout << foo_.x_ << endl;}
private:
Foo& foo_;
};
struct Bar2 {
Bar2(shared_ptr<Foo> _foo) : foo_{move(_foo)} {}
void print_foo() {cout << foo_->x_ << std::endl;}
private:
shared_ptr<Foo> foo_;
};
int main()
{
Foo f1{1};
shared_ptr<Foo> f2 = make_shared<Foo>(2);
Bar1 b1(f1);
b1.print_foo();
Bar2 b2(f2);
b2.print_foo();
return 0;
}
我认为,Bar1为用户提供了更多关于如何管理Foo的生命的自由,并且它可能更有效。但它会在一个不确定的(不知道这是在这里正确的字)的状态,当实例富到foo_是指被破坏。
处理这种情况的首选方式是什么?为什么?
我认为处理这种情况的首选方法取决于具体情况。正如您所确定的那样,Bar1
在使用寿命内为用户提供了更大的自由度Foo
,并且更加危险。它也效率更高(略),但可能不足以引起关注。
如果您知道一个事实(和/或可以证明)Foo
将永远超过所有Bar
对象(也许您Foo
在堆栈中分配了要使用的对象main
),那么使用没问题Bar1
。如果您不确定,那Bar2
将是一条路。尽管语义可能是错误的Bar2
(也许您不想Bar
让自己Foo
活着)。
这使我们想到了第三个选择:weak_ptr
。这将使用户可以控制的生存期Foo
,但Bar
在Foo
销毁时仍然允许具有已定义的行为。
struct Bar3 {
Bar3(std::weak_ptr<Foo> _foo) : foo_(_foo) {}
void print_foo_v1() {
// throws if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_);
std::cout << foo->x_ << std::endl;
}
void print_foo_v2() {
// returns nullptr if foo_'s object has been destroyed
std::shared_ptr<Foo> foo(foo_.lock());
if (foo) {
std::cout << foo->x_ << std::endl;
}
}
private:
std::weak_ptr<Foo> foo_;
};
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句