c++ - 共享指针指向的对象的生命周期
问题描述
举个例子
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
ininitB()
超出范围,一个函数完成执行。但是有一个指向它的共享指针。当 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
有趣的是,你有没有发现发生了什么?有A's DTOR
2s。std::make_share<A>(a)
实际上制作一个副本,a
然后制作一个shared_ptr
to a
。由于我们没有定义复制赋值运算符/构造函数,编译器会自动生成一个,这就是我们只有一个的原因A's CTOR
。因此,即使我无法想象你会在哪里这样做,它也会有一个有效的 A 实例。
推荐阅读
- javascript - 抓紧时间改变DIV
- python - 如何使用类更新 TKinter 标签图像(使用 Config() 方法动态更新)
- r - 将 R 数据框输出到 .txt 文件 - 对齐正值和负值
- karate - .txt 文件中的场景大纲示例(.txt 文件中的每一行都是 JSON)
- ruby-on-rails - 如何从具有 ActiveRecord 关系 2 级深的 rails api 返回响应?
- android - android生命周期方法在同一应用内或应用之间的操作是否存在差异
- ansible - 使用 with_items 和 vars 的 Ansible 合并字典仅存储最后一项
- swiftui - 你能在 SwiftUI 选择器中更改选择视图的颜色吗
- google-tag-manager - 单页应用程序和谷歌标签管理器
- r - R在有或没有分隔符的列中分隔字符串