从成员函数返回向上转换版本的shared_ptr问题

发布于 2024-10-27 17:08:55 字数 1338 浏览 3 评论 0原文

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

这对于裸指针来说效果很好。我刚刚返回了一个dynamic_cast(this)。然而,我在这里有点困惑,因为即使使用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 调用在这一点上似乎在我使用它的所有其他情况下都工作得很好。也许有人可以准确解释是什么原因导致第一个示例崩溃而第二个示例正常工作。我会给这个答案打分。

I've recently been trying out shared_ptr and I've run across a bit of a weird case. What I want is a template member function which is capable of returning a shared_ptr of its derived type. I'm running visual studio 2010 which has access to some of the new c++0x standard, but I assume the boost shared_ptr behaves similarly.

This worked fine with bare pointers. I just returned a dynamic_cast<DerivedClass*>(this). I'm kind of stumped here, however, because even using enable_shared_from_this the object attempts to delete itself after the function is called (which is bad). I am probably approaching this wrong, but I'd like to work out how to simulate the bare pointer equivalent (which was working) of the following (this is the code I'm having trouble with).

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

edit: It seems the function works correctly, the problem was with how I was using it. It is bad, for example to do the following:

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

This is not a problem:

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

I'm not entirely sure if it's a problem with converting to the same type, or a reference counting issue. In any case, I was doing something dumb and it broke, avoiding the unnecessary getType call at that point seems to work fine in every other case I am using it. Maybe someone can explain precisely what causes the first example to break with the second example working. I'll assign points to that answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

離殇 2024-11-03 17:08:55

为了扩展 Stuart 的答案并(可能)解释您崩溃的原因,我最好的猜测是您在堆栈分配的实例上调用 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,课程。

To expand on Stuart's answer and to (possibly) explain why you were crashing, my best guess is that you were calling getType on a stack-alloc'd instance. It's a major pitfall to using 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;
}

The reason this occurs is because the reference count of d2 is zero when it's on the stack. Calling shared_from_this returns a shared_ptr that increments the reference count to one. Once this pointer goes out of scope, it decrements its count to zero, which then attempts to delete the instance, which, of course, is on the stack.

The only way that I can think of protecting yourself from this, off the top of my head, is to make all constructors protected or private and provide static functions that dynamically allocate any instances, returning shared_ptrs, of course.

眼泪淡了忧伤 2024-11-03 17:08:55

就其价值而言,我没有遇到您通过以下最小可编译示例描述的问题(看起来像您上面描述的代码):

#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;
}

这对您来说会崩溃吗?

For what it's worth, I don't experience the problem you're describing with the following minimal compileable example (which looks like the code you describe above):

#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;
}

Does this crash for you?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文