shared_ptr问题从成员函数返回上传版本

时间:2011-03-28 11:26:47

标签: c++ c++11 this shared-ptr

我最近一直在尝试使用shared_ptr,而且我遇到了一些奇怪的情况。我想要的是一个模板成员函数,它能够返回其派生类型的shared_ptr。我正在运行visual studio 2010,它可以访问一些新的c ++ 0x标准,但我认为boost shared_ptr的行为类似。

这很好用的指针。我刚刚返回了一个dynamic_cast< DerivedClass *>(这个)。但是,我有点难过,因为即使使用enable_shared_from_this,对象也会在调用函数后尝试删除自身(这很糟糕)。我可能正在接近这个错误,但我想弄清楚如何模拟以下的裸指针等效(这是有效的)(这是我遇到问题的代码)。

//assume we have a virtual function as well.
class BaseClass : public std::enable_shared_from_this<BaseClass>
{
  ....
  template<typename DerivedClass>
  std::shared_ptr<DerivedClass> BaseClass::getThis(){
     //I had some assert code here to ensure typeid matched
     return std::dynamic_pointer_cast<DerivedClass>(shared_from_this());
  }
}

编辑:似乎功能正常,问题在于我如何使用它。例如,执行以下操作很糟糕:

std::shared_ptr<DerivedClass> p = std::make_shared<DerivedClass>();
p->getType<DerivedClass>->someOtherFunctionOnlyInTheDerivedClass();

这不是问题:

std::shared_ptr<BaseClass> p = std::make_shared<DerivedClass>();
p->getType<DerivedClass>->someOtherFunctionOnlyInTheDerivedClass();

我不完全确定转换为相同类型或引用计数问题是否存在问题。在任何情况下,我都做了一些愚蠢的事情并且它已经破坏了,避免了那时不必要的getType调用似乎在我使用它的其他每种情况下都能正常工作。也许有人可以准确地解释是什么原因导致第一个例子与第二个例子一起工作。我将为这个答案分配点数。

2 个答案:

答案 0 :(得分:5)

为了扩展Stuart的答案并(可能)解释你崩溃的原因,我最好的猜测是你在stack-alloc'd实例上调用getType。使用enable_shared_from_this是一个主要的陷阱。

#include <memory>

class Base : public std::enable_shared_from_this<Base>
{
public:
    virtual ~Base() {}

    template <typename D>
    std::shared_ptr<D> getType()
    {
        return std::dynamic_pointer_cast<D>(shared_from_this());
    }
};

class Derived : public Base
{
public:
    void f() {}
};

int main()
{
    std::shared_ptr<Derived> d = std::make_shared<Derived>();
    d->getType<Derived>()->f(); // fine

    Derived d2;
    Base* p = &d2;
    p->getType<Derived()>->f(); // will attempt to delete d2 after f() returns.

    return 0;
}

发生这种情况的原因是因为当它在堆栈上时,d2的引用计数为零。调用shared_from_this会返回shared_ptr,将引用计数增加到1。一旦这个指针超出范围,它会将其计数减少到零,然后尝试删除实例,当然,该实例位于堆栈上。

我能想到保护自己的唯一方法就是让所有构造函数都受到保护或私有,并提供动态分配任何实例的静态函数,返回shared_ptr个当然。

答案 1 :(得分:2)

对于它的价值,我没有遇到你用以下最小可编译示例描述的问题(看起来像上面描述的代码):

#include <memory>

class Base : public std::enable_shared_from_this<Base>
{
public:
    virtual ~Base() {}

    template <typename D>
    std::shared_ptr<D> getType()
    {
        return std::dynamic_pointer_cast<D>(shared_from_this());
    }
};

class Derived : public Base
{
public:
    void f() {}
};

int main()
{
    std::shared_ptr<Derived> d = std::make_shared<Derived>();
    d->getType<Derived>()->f();
    return 0;
}

这会让你崩溃吗?