对智能指针范围的困惑
Confusion about scope of smart pointers
假设我有以下函数和一些假设的 class Obj
可以保存指向类型 Foo
:
对象的(智能)指针
class Obj {
public:
void setFoo(std::shared_ptr<Foo>);
std::shared_ptr<Foo> foo;
};
Obj::setFoo(std::shared_ptr<Foo> fooPtr) {
foo = fooPtr;
}
Obj* getObj() {
std::shared_ptr<Foo> fooPtr = std::make_shared<Foo>(new Foo());
Obj *obj = new Obj();
obj->setFoo(fooPtr);
return obj;
}
我的智能指针什么时候会被删除?
- 当我们从
getObj
中 return 因为它现在超出了函数的范围并且 obj
没有指向 "smartly"?
- 每当以后在我的程序中删除
obj
时?
我的测试让我认为它是 2.,但一位同事认为它是 1.
我找不到可以回答我的问题的文档,因为我阅读的所有关于智能指针的解释都没有对指针做任何会使其脱离其创建者范围的事情...
在fooPtr
中分配和保存的指针在getObj()
结束时没有被销毁,因为在setFoo()
之后, 两个个包含它的共享指针。
在 getObj()
结束时,第一个包含共享指针的指针被销毁(fooPtr
)但另一个仍然存在:Obj
对象的 foo
成员由 obj
.
指出
obj
由 getObj()
返回,因此第二个共享指针在 getObj()
.
的末尾存在
请注意 std::make_shared<Foo>(new Foo())
是一种反模式。如果 std::make_shared
抛出异常(例如 std::bad_alloc
)或 std::make_shared<Foo>
调用的 Foo
构造函数抛出异常,则 new Foo()
的结果永远不会被删除并因此泄漏内存.
此外,obj
未使用智能指针进行管理,因此可能会泄漏。
更安全的版本:
struct Foo {};
class Obj : std::enable_shared_from_this<Obj> {
Foo foo;
public:
void setFoo(Foo const& f) {
foo = f;
}
std::shared_ptr<Foo> getFoo() {
return std::shared_ptr<Foo>(this->shared_from_this(), &foo); // aliasing constructor.
}
};
std::shared_ptr<Obj> getObj() {
auto obj = std::make_shared<Obj>();
// obj->setFoo(Foo(<args>); // if necessary
return obj;
}
int main() {
std::shared_ptr<Obj> obj = getObj();
std::shared_ptr<Foo> foo = obj->getFoo();
}
请注意,这里的共享指针 obj
和 foo
都引用相同的底层对象 Obj
,因为使用了 std::shared_ptr
别名构造函数。通过 std::shared_ptr
管理对象后,您可以为其成员创建 std::shared_ptr
,而不必将这些成员转换为 std::shared_ptr
.
假设我有以下函数和一些假设的 class Obj
可以保存指向类型 Foo
:
class Obj {
public:
void setFoo(std::shared_ptr<Foo>);
std::shared_ptr<Foo> foo;
};
Obj::setFoo(std::shared_ptr<Foo> fooPtr) {
foo = fooPtr;
}
Obj* getObj() {
std::shared_ptr<Foo> fooPtr = std::make_shared<Foo>(new Foo());
Obj *obj = new Obj();
obj->setFoo(fooPtr);
return obj;
}
我的智能指针什么时候会被删除?
- 当我们从
getObj
中 return 因为它现在超出了函数的范围并且obj
没有指向 "smartly"? - 每当以后在我的程序中删除
obj
时?
我的测试让我认为它是 2.,但一位同事认为它是 1.
我找不到可以回答我的问题的文档,因为我阅读的所有关于智能指针的解释都没有对指针做任何会使其脱离其创建者范围的事情...
在fooPtr
中分配和保存的指针在getObj()
结束时没有被销毁,因为在setFoo()
之后, 两个个包含它的共享指针。
在 getObj()
结束时,第一个包含共享指针的指针被销毁(fooPtr
)但另一个仍然存在:Obj
对象的 foo
成员由 obj
.
obj
由 getObj()
返回,因此第二个共享指针在 getObj()
.
请注意 std::make_shared<Foo>(new Foo())
是一种反模式。如果 std::make_shared
抛出异常(例如 std::bad_alloc
)或 std::make_shared<Foo>
调用的 Foo
构造函数抛出异常,则 new Foo()
的结果永远不会被删除并因此泄漏内存.
此外,obj
未使用智能指针进行管理,因此可能会泄漏。
更安全的版本:
struct Foo {};
class Obj : std::enable_shared_from_this<Obj> {
Foo foo;
public:
void setFoo(Foo const& f) {
foo = f;
}
std::shared_ptr<Foo> getFoo() {
return std::shared_ptr<Foo>(this->shared_from_this(), &foo); // aliasing constructor.
}
};
std::shared_ptr<Obj> getObj() {
auto obj = std::make_shared<Obj>();
// obj->setFoo(Foo(<args>); // if necessary
return obj;
}
int main() {
std::shared_ptr<Obj> obj = getObj();
std::shared_ptr<Foo> foo = obj->getFoo();
}
请注意,这里的共享指针 obj
和 foo
都引用相同的底层对象 Obj
,因为使用了 std::shared_ptr
别名构造函数。通过 std::shared_ptr
管理对象后,您可以为其成员创建 std::shared_ptr
,而不必将这些成员转换为 std::shared_ptr
.