共享指针指向的对象的生命周期
Lifetime of object pointed to by shared pointer
举个例子
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();
initB()
中的局部变量 a
超出范围一个函数完成执行。但是有一个指向它的共享指针。当 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
。由于我们没有定义复制赋值 operator/constructor,编译器会自动生成一个,这就是为什么我们只有一个 A's CTOR
。因此,即使我无法想象您会在哪个地方执行此操作,它也会有一个有效的 A 实例。
举个例子
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();
initB()
中的局部变量 a
超出范围一个函数完成执行。但是有一个指向它的共享指针。当 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
。由于我们没有定义复制赋值 operator/constructor,编译器会自动生成一个,这就是为什么我们只有一个 A's CTOR
。因此,即使我无法想象您会在哪个地方执行此操作,它也会有一个有效的 A 实例。