如何解决共享指针指向的对象的生命周期
以下面的例子
struct A {
int x = 0;
};
struct B {
std::shared_ptr<A> mA;
void setA(std::shared_ptr<A> a) {
mA = a;
}
};
struct C {
B initB() {
A a;
A *aPtr = &a;
B b;
b.setA(std::make_shared<A>(aPtr));
return b;
}
};
现在在 main()
方法中
C c;
B b = c.initB();
a
中的局部变量 initB()
超出了函数完成执行的范围。但是有一个共享指针指向它。当 a 超出范围时,共享指针指向的对象会被删除吗?
最后 *(b.mA)
会给出一个有效的 A
实例吗?
解决方法
首先,这不能编译。
B initB() {
A a;
A* aPtr = &a;
B b;
b.setA(std::make_shared<A>(/*aPtr*/a););
return b;
}
您必须传递正在共享的实际对象,而不是指向它的指针。现在,为了找到这个问题的答案,我们可以为每个函数编写通知程序,并添加构造函数和析构函数,以便我们可以看到发生了什么。
#include <memory>
#include <iostream>
struct A {
int x = 0;
A() {
std::cout << "A's CTOR" << std::endl;
}
~A() {
std::cout << "A's DTOR" << std::endl;
}
};
struct B {
B() {
std::cout << "B's CTOR" << std::endl;
}
~B() {
std::cout << "B's DTOR" << std::endl;
}
std::shared_ptr<A> mA;
void setA(std::shared_ptr<A> a) {
std::cout << "Entering setA()" << std::endl;
mA = a;
std::cout << "Exiting setA()" << std::endl;
}
};
struct C {
C() {
std::cout << "C's CTOR" << std::endl;
}
~C() {
std::cout << "C's DTOR" << std::endl;
}
B initB() {
std::cout << "Entering initB()" << std::endl;
A a;
A* aPtr = &a;
B b;
b.setA(std::make_shared<A>(/*aPtr*/a));
std::cout << "Exiting initB()" << std::endl;
return b;
}
};
int main() {
std::cout << "Entering Main" << std::endl;
C c;
B b = c.initB();
std::cout << "Exiting Main" << std::endl;
return 0;
}
输出:
Entering Main
C's CTOR
Entering initB()
A's CTOR
B's CTOR
Entering setA()
Exiting setA()
Exiting initB()
B's DTOR
A's DTOR
Exiting Main
B's DTOR
A's DTOR
C's DTOR
有趣,你有没有发现发生了什么?有 2 个 A's DTOR
。 std::make_share<A>(a)
实际上制作了 a
的副本,然后制作了 shared_ptr
到 a
。由于我们没有定义复制赋值运算符/构造函数,编译器会自动生成一个,这就是为什么我们只有一个 A's CTOR
。所以即使我无法想象你会在哪个地方这样做,它也会有一个有效的 A 实例。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。