此的std :: shared_ptr


101

我目前正在尝试学习如何使用智能指针。但是,在进行一些实验时,我发现以下情况,无法找到令人满意的解决方案:

假设您有一个类A的对象是类B(孩子)的对象的父对象,但两者应该彼此了解:

class A;
class B;

class A
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children->push_back(child);

        // How to do pass the pointer correctly?
        // child->setParent(this);  // wrong
        //                  ^^^^
    }

private:        
    std::list<std::shared_ptr<B>> children;
};

class B
{
public:
    setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    };

private:
    std::shared_ptr<A> parent;
};

问题是,类A的对象如何std::shared_ptr将自身(this)的a传递给它的子对象?

有用于升压共享指针(解决方案获得一个boost::shared_ptrthis),但如何使用来处理std::智能指针?


2
与其他任何工具一样,您必须在适当的时候使用它。不是
YePhIkK 2012年

与此类似。看这里
juanchopanza 2012年

1
在该抽象级别上,这是一个问题。您甚至都不知道“ this”指向堆上的内存。
沃恩·卡托

好吧,语言不是,但是可以。只要您跟踪什么在哪里,就可以了。
亚历克斯

Answers:


168

std::enable_shared_from_this只是为了这个目的。您可以.shared_from_this()从中继承,也可以从类内部调用。此外,您还在此处创建循环依赖关系,这可能导致资源泄漏。可以使用来解决std::weak_ptr。因此,您的代码可能看起来像这样(假设子代依赖于父代的存在而不是相反):

class A;
class B;

class A
    : public std::enable_shared_from_this<A>
{
public:
    void addChild(std::shared_ptr<B> child)
    {
        children.push_back(child);

        // like this
        child->setParent(shared_from_this());  // ok
        //               ^^^^^^^^^^^^^^^^^^
    }

private:     
    // note weak_ptr   
    std::list<std::weak_ptr<B>> children;
    //             ^^^^^^^^
};

class B
{
public:
    void setParent(std::shared_ptr<A> parent)
    {
        this->parent = parent;
    }

private:
    std::shared_ptr<A> parent;
};

但是请注意,调用.shared_from_this()需要在调用时this归所有者所有std::shared_ptr。这意味着您不能再在堆栈上创建此类对象,并且通常无法.shared_from_this()在构造函数或析构函数内调用。


1
感谢您的解释并指出我的循环依赖问题。
伊卡洛斯

@Deduplicator是什么意思?
尤里·基列奇

尝试构建shared_ptr基于默认构造的基础,shared_ptr以及您想要将其指向的任何内容……
Deduplicator 2015年

1
@Deduplicator是一个,请原谅我的双关语,没有意义的共享指针。该构造函数旨在与指向托管对象或其基础的成员的指针一起使用。无论如何,您的意思是(对不起)?这些非拥有shared_ptr者与这个问题无关。shared_from_this的前提条件清楚地表明,对象必须shared_ptr在调用时由某些人拥有(不仅仅是指向)。
yuri kgchek 2015年

1
@kazarey shared_ptr在调用时需要所有权,但是在典型的使用模式中,例如shared_ptr<Foo> p(new Foo());shared_ptr仅当对象完全构建后才假定拥有所有权。可以通过shared_ptr在中初始化的构造函数创建this并将其存储在非本地的地方(例如,在引用参数中)来避免这种情况,从而在构造函数完成时不会死亡。但是这种复杂的情况不太可能发生。
yuri kgchek 2016年

9

您在设计中有几个问题,似乎是由于您对智能指针的误解而引起的。

智能指针用于声明所有权。您通过声明父母双方都拥有所有孩子,而且每个孩子都拥有自己的父母来打破这一点。两者都不是真的。

另外,您将在中返回弱指针getChild()。这样做是在声明调用方不必关心所有权。现在这可能是非常有限的,但是这样做,您必须确保在保持任何弱指针的情况下不会破坏有问题的孩子,如果您使用智能指针,则它将自己进行整理。

还有最后一件事。通常,当您接受新实体时,通常应该接受原始指针。智能指针对于在父母之间交换孩子有其自身的含义,但是对于一般用法,您应该接受原始指针。


看起来我真的需要澄清我对智能指针的理解。感谢您指出这一点。
伊卡洛斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.