首页 > 解决方案 > 共享指针指向的对象的生命周期

问题描述

举个例子

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();

局部变量aininitB()超出范围,一个函数完成执行。但是有一个指向它的共享指针。当 a 超出范围时,共享指针指向的对象会被删除吗?最后将*(b.mA)给出一个有效的实例A

标签: c++c++11shared-ptrsmart-pointers

解决方案


首先,这不会编译。

    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 DTOR2s。std::make_share<A>(a)实际上制作一个副本,a然后制作一个shared_ptrto a。由于我们没有定义复制赋值运算符/构造函数,编译器会自动生成一个,这就是我们只有一个的原因A's CTOR。因此,即使我无法想象你会在哪里这样做,它也会有一个有效的 A 实例。


推荐阅读