如果涉及到`this`,则无法在构造函数中初始化Shared_ptr

时间:2016-06-20 07:48:58

标签: c++ shared-ptr

我有一些像这样构造的代码:

#include <memory>
#include <vector>

using namespace std;
struct demo {
    vector<shared_ptr<demo>> foo{shared_ptr<demo>(this)};
    void append(){
        foo.push_back(make_shared<demo>());
    }
};

demo dummy(/* accept some arguments */){
    demo a{};
    a.append();
    return a;
}

int main()
{
    demo bar=dummy();
    return 0;
}

虚函数只是根据新构建的演示实例上的参数进行一些处理并返回它。 (我很确定以上内容足以揭露问题)

它编译良好,没有错误,但它不会自动终止。 (我在Win7上使用G ++的MinGW)。

然后我尝试解决。我添加了一个复制构造函数(以及一个显式的默认构造函数),然后使用new仅在main函数中保留一个指向demo的指针。因此代码将类似于:

...
struct demo {
    vector<shared_ptr<demo>> foo {shared_ptr<demo>(this)};
    void append() {
        foo.push_back(make_shared<demo>());
    }
    demo(){
    };
    demo(const demo& instance): foo(instance.foo) {
    }
};
...
int main()
{
//    demo bar=dummy();
    demo* bar=new demo(dummy());
    delete bar;
    return 0;
}

然后就行了。但我仍然怀疑这些线背后的机制。您能解释一下new构造变量和通常声明变量之间的区别吗?

编辑:所以最终还是将push_back this作为构造函数中的struct成员导入到向量中? (由于这个原因,这是因为我的矢量的其余部分存储了除第一个之外的所有shared_ptr,换句话说,即使向量pop_back为空,它仍然可以返回{{1 }})

2 个答案:

答案 0 :(得分:3)

这是一个更简单的示例,可以重现您的问题:

struct demo {
    shared_ptr<demo> foo{this};
};

int main()
{
    demo bar;
}

问题是您在成员中存储了this的共享指针。因此,当一个demo实例被销毁时,共享指针会递减,当共享指针递减到零时,它将再次删除该对象,从而导致未定义的行为。

即使问题不存在,仍然存在bar是自动对象的问题。并且您可能没有共享指向自动对象的指针。但bar确实创建了一个指向自身的共享指针。

demo* bar=new demo(dummy());
delete bar;

这样更好,因为现在对象(由bar指向)具有动态存储,因此您可能有一个共享指针。您当然必须修复dummy以不创建自动demo实例。

此外,您可能没有明确delete demo的实例,因为内部有一个共享指向它自己。 &#34;正确&#34;处理demo实例的方法是删除共享指针,然后处理删除:

demo* bar=new demo(dummy());
bar->foo.clear();      // this is for your vector version
//bar->foo = nullptr;  // this is for my minimized example above
// object pointed by bar no longer exists
// (unless the shared pointer was copied and exists elsewhere)

但是,我觉得这个设计很混乱,不推荐它。您应该重新考虑为什么存储共享指针this

答案 1 :(得分:0)

在堆栈上创建a或让shared_ptr管理其生命周期,但不能同时执行这两项操作。当堆栈消失时,堆栈上的对象消失。

相关问题