enable_shared_from_this 和堆栈上的对象

发布于 2024-09-16 12:19:48 字数 398 浏览 7 评论 0原文

有没有办法防止对堆栈分配的对象调用shared_from_this()?

该enable_shared_from_this<>基类列表中的内容对于类用户来说是一个强有力的指标,但是有没有办法强制执行正确的用法?

示例代码:

class C : public enable_shared_from_this<C>
{
public:
  shared_ptr<C> method() { return shared_from_this(); }
};

void func()
{
  C c;
  shared_ptr<C> ptr = c.method(); // exception coming from shared_from_this()
}

Is there a way to prevent shared_from_this() call for a stack-allocated object ?

The enable_shared_from_this<> in the base classes list is a strong indicator for class user, but is there a way to enforce the correct usage ?

Example code:

class C : public enable_shared_from_this<C>
{
public:
  shared_ptr<C> method() { return shared_from_this(); }
};

void func()
{
  C c;
  shared_ptr<C> ptr = c.method(); // exception coming from shared_from_this()
}

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

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

发布评论

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

评论(2

赠我空喜 2024-09-23 12:19:48

因此,为了防止这个问题,您可以将构造函数设置为私有,并且只提供返回shared_ptr的创建函数 - 这样就无法在堆栈上分配对象,如下所示:

class C : public enable_shared_from_this<C>
{
public:
  static shared_ptr<C> create() { return shared_ptr<C>(new C() ); }
  shared_ptr<C> method() { shared_from_this(); }

private:
  C() {...}

  // Make operator= and C(const C&) private unimplemented
  // so the used cant do bad things like C c( * c_ptr );
  C& operator=( const C & );
  C( const C & );
};


void func()
{
  C c; // This doesn't compile
  shared_ptr<C> ptr = c.method(); // So you can never get this
}

void altfunc()
{
  shared_ptr<C> c_ptr = C::create();
  C & c_ref = *c;
  shared_ptr<C>  ptr = c_ref.method(); // OK
}

如果您发现自己希望有一个operator=< /code> 您可以使用私有实现的复制构造函数提供克隆函数,如下所示

// This goes in class C
shared_ptr<C> C::clone() const
{
  return shared_ptr<C>( new C(*this) );
}

// This is how you can use it
shared_ptr<C> c2 = c1->clone();

So to protect against this problem you can make your constructors private and only provide creation functions that return shared_ptr - this way the object can't be allocated on the stack, like this:

class C : public enable_shared_from_this<C>
{
public:
  static shared_ptr<C> create() { return shared_ptr<C>(new C() ); }
  shared_ptr<C> method() { shared_from_this(); }

private:
  C() {...}

  // Make operator= and C(const C&) private unimplemented
  // so the used cant do bad things like C c( * c_ptr );
  C& operator=( const C & );
  C( const C & );
};


void func()
{
  C c; // This doesn't compile
  shared_ptr<C> ptr = c.method(); // So you can never get this
}

void altfunc()
{
  shared_ptr<C> c_ptr = C::create();
  C & c_ref = *c;
  shared_ptr<C>  ptr = c_ref.method(); // OK
}

If you find yourself wishing for an operator= you can provide a clone function using a private implemented copy constructor, something like this

// This goes in class C
shared_ptr<C> C::clone() const
{
  return shared_ptr<C>( new C(*this) );
}

// This is how you can use it
shared_ptr<C> c2 = c1->clone();
还不是爱你 2024-09-23 12:19:48

我找到了解决方案。

在 Dune 库中,他们使用堆栈兼容的 enable_shared_from_this 类模板适配。

检查原始源代码 此处 或使用快速复制和粘贴来检查我的示例代码清理:

#include <cstdio>
#include <cassert>
#include <memory>
#include <iostream>

template<class T>
struct null_deleter
{
    void operator() (T*) const {}
};
template<typename T>
inline std::shared_ptr<T> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T>(&t, null_deleter<T>());
}

template<typename T, typename T2>
inline std::shared_ptr<T2> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T2>(dynamic_cast<T2*>(&t), null_deleter<T2>());
}

template<typename T>
class stack_compatible_enable_shared_from_this
: public std::enable_shared_from_this<T>
{
public:
    std::shared_ptr<T> shared_from_this()
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*static_cast<T*>(this));
            return _local_ptr;
        }
    }
    
    std::shared_ptr<const T> shared_from_this() const
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*const_cast<T*>(static_cast<const T*>(this)));
            return _local_ptr;
        }
    }
    
private:
    
    mutable std::shared_ptr<T> _local_ptr;
};

struct MyObj : public stack_compatible_enable_shared_from_this<MyObj>{};

int main (int argc, char **argv) {
    //std::shared_ptr<MyObj> so = std::make_shared<MyObj>(6);
    MyObj o{};
    auto * so = &o;
    {
        auto l = std::weak_ptr<MyObj>(so->shared_from_this());
        auto shared = l.lock();
        if (shared) { } //use it
    }
}

I found the solution.

In Dune library they use stack-compatible enable_shared_from_this class template adaptation.

Check the original source code here or check my example with the quick copy&paste & cleanup of code:

#include <cstdio>
#include <cassert>
#include <memory>
#include <iostream>

template<class T>
struct null_deleter
{
    void operator() (T*) const {}
};
template<typename T>
inline std::shared_ptr<T> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T>(&t, null_deleter<T>());
}

template<typename T, typename T2>
inline std::shared_ptr<T2> stackobject_to_shared_ptr(T & t)
{
    return std::shared_ptr<T2>(dynamic_cast<T2*>(&t), null_deleter<T2>());
}

template<typename T>
class stack_compatible_enable_shared_from_this
: public std::enable_shared_from_this<T>
{
public:
    std::shared_ptr<T> shared_from_this()
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*static_cast<T*>(this));
            return _local_ptr;
        }
    }
    
    std::shared_ptr<const T> shared_from_this() const
    {
        try
        {
            return std::enable_shared_from_this<T>::shared_from_this();
        }
        catch (std::bad_weak_ptr&)
        {
            _local_ptr = stackobject_to_shared_ptr(*const_cast<T*>(static_cast<const T*>(this)));
            return _local_ptr;
        }
    }
    
private:
    
    mutable std::shared_ptr<T> _local_ptr;
};

struct MyObj : public stack_compatible_enable_shared_from_this<MyObj>{};

int main (int argc, char **argv) {
    //std::shared_ptr<MyObj> so = std::make_shared<MyObj>(6);
    MyObj o{};
    auto * so = &o;
    {
        auto l = std::weak_ptr<MyObj>(so->shared_from_this());
        auto shared = l.lock();
        if (shared) { } //use it
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文