一旦引用计数达到 0,就让shared_ptr 调用成员函数

发布于 2024-09-06 04:23:59 字数 492 浏览 1 评论 0原文

我正在为不能与 DuplicateHandle 一起使用的 HANDLE 创建一个包装器,因此我尝试将句柄包装在共享指针中。

想象一下以下代码:

class CWrapper
{
public:
    CWrapper() :
        m_pHandle(new HANDLE, &CWrapper::Close)
    {
        //code to open handle
    }

private:
    void Close() 
    { 
        //code to close handle
    }

    std::shared_ptr<HANDLE> m_pHandle;
}

我还尝试使用 HANDLE 参数创建 close (不理想)。无论哪种方式,我都会收到编译器错误“Term 不会计算为采用 0 个参数的函数”。这是因为隐式的 this 指针吗?我该如何解决这个问题?如何从共享指针调用成员函数?

I'm creating a wrapper for a HANDLE that does not work with DuplicateHandle, so instead I am trying to wrap the handle in a shared_ptr.

Imagine the following code:

class CWrapper
{
public:
    CWrapper() :
        m_pHandle(new HANDLE, &CWrapper::Close)
    {
        //code to open handle
    }

private:
    void Close() 
    { 
        //code to close handle
    }

    std::shared_ptr<HANDLE> m_pHandle;
}

I have also tried creating close with a HANDLE parameter (not ideal). Either way, I get the compiler error "Term does not evaluate to a function taking 0 arguments". Is this because of the implicit this pointer? How do I fix this? How do I call a member function from the shared pointer?

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

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

发布评论

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

评论(5

清欢 2024-09-13 04:24:10

在 boost::shared_ptr 文档中查找 deleter 。我找不到它的直接链接,但基本上它是一个函子,当 ref 为 0 时被调用。

Look for deleter in boost::shared_ptr docs. I couldn't find a direct link to it, but basically it is a functor that is called when the ref is 0.

且行且努力 2024-09-13 04:24:08

我还没有测试过,但是根据 shoosh 提出的想法,您也许可以传递这样的成员函数:

void Class::myDeleteMember(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, boost::bind(&Class::myDeleteMember, _1)); 

I haven't tested it, but based on the idea presented by shoosh, you may be able to pass a member function like this:

void Class::myDeleteMember(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, boost::bind(&Class::myDeleteMember, _1)); 
烧了回忆取暖 2024-09-13 04:24:06

如果您需要从 Close 中访问非静态成员,则需要正确绑定其 this 参数

CWrapper() :
   m_pHandle(new HANDLE, boost::bind(&CWrapper::Close, this, _1)) {
    //code to open handle
}

,但这包含一个隐藏的错误。您的对象是可复制的,并且您将删除器绑定到 *this 的对象。该句柄与您创建的第一个包装器相关联,但如果您复制该包装器,该句柄将被共享,但与第一个包装器相关联,该第一个包装器可能不再存在:

CWrapper getWrapper() { CWrapper w; return w;  }
CWrapper x = getWrapper();

执行该代码后,x将被销毁,行为未定义,因为 x 内部句柄指针的销毁将尝试使用 w 构造函数调用中绑定的对象 - 然而该对象并不不存在了!

解决这个问题的方法是将与句柄关联的数据存储在分配的对象本身中,而不是尝试将其存储在顶级句柄对象中,如下面的代码所示。

class CWrapper
{
public:
  CWrapper():m_pHandle(new CHandle)
  { }

private:
    // This class cannot be copied
    class CHandle : boost::noncopyable {
      friend class CWrapper;

      CHandle() 
        :m_pHandle(new HANDLE) {
          // code to open handle
      }

      ~CHandle() {
        // code to close this handle, making use of 
        // auxilary data for whatever reason
      }

    private:
      boost::scoped_ptr<HANDLE> m_pHandle;
      // auxilary data associated with the handle...
    };

    boost::shared_ptr<CHandle> m_pHandle;
};

辅助数据不再存储在句柄中,而是以及包装器的所有副本之间共享的数据。共享数据本身是使用其正常的构造函数和析构函数创建和销毁的。

CWrapper getHandle() { return myHandle; }
CWrapper w = getHandle();

最后一个退出的包装器将销毁句柄,该句柄在所有包装器之间显式共享。

If you need to access non-static members from within Close you need to bind its this argument properly

CWrapper() :
   m_pHandle(new HANDLE, boost::bind(&CWrapper::Close, this, _1)) {
    //code to open handle
}

This, however contains a hidden bug. Your object is copyable, and you bind the deleter to the object of *this. The handle is associated with the first wrapper you create, but if you copy the wrapper, the handle is shared but associated with the first wrapper, which may not exist anymore:

CWrapper getWrapper() { CWrapper w; return w;  }
CWrapper x = getWrapper();

After that code was executed and x is going to be destroyed, behavior is undefined because x's destruction of the internal handle pointer will try to use the object bound in w's constructor invokation - however that object doesn't exist anymore!

A solution to this can be to store the data associated with the handle in the allocated object itself, instead of trying to store it in the toplevel handle object, like in the following code

class CWrapper
{
public:
  CWrapper():m_pHandle(new CHandle)
  { }

private:
    // This class cannot be copied
    class CHandle : boost::noncopyable {
      friend class CWrapper;

      CHandle() 
        :m_pHandle(new HANDLE) {
          // code to open handle
      }

      ~CHandle() {
        // code to close this handle, making use of 
        // auxilary data for whatever reason
      }

    private:
      boost::scoped_ptr<HANDLE> m_pHandle;
      // auxilary data associated with the handle...
    };

    boost::shared_ptr<CHandle> m_pHandle;
};

The auxilary data is not not stored in the handle anymore, but together with the data that's shared among all copy of the wrapper. The shared data itself is created and destroyed using its normal constructor and destructor.

CWrapper getHandle() { return myHandle; }
CWrapper w = getHandle();

The last wrapper going out of life will destroy the handle, which is explicitly shared among all wrappers.

千寻… 2024-09-13 04:24:05

我认为你的抽象方式是错误的。

shared_ptr 为您提供了一个可复制的共享资源“句柄”,但该共享资源本身无法复制。将 shared_ptr 与删除时不执行自身清理的类型一起使用并不是最佳用途。

如果让你的类有单一责任在其析构函数中正确清理这个固有的不可复制资源,那么你可以使用shared_ptr来提供共享所有权,这就是它的单一责任。 (我认为 HANDLE 是不可复制的,就像您尝试制作 HANDLE 的简单副本一样,副本不能被视为独立;最后一个副本必须正确关闭因此副本的所有者需要了解存在的其他副本。)

class CWrapper
{
public:
    CWrapper()
    {
        // code to open handle
    }

    ~CWrapper()
    {
        // code to close handle
    }

private:
    // prevent copying
    CWrapper(const CWrapper&);
    CWrapper& operator=(const CWrapper&);

    HANDLE mHandle;
};

现在在需要共享句柄的地方使用 shared_ptr ,如果您认为这太冗长,可以使用 typedef 。

恕我直言,自定义删除器是一个过于复杂的解决方案。

I think you have your abstractions the wrong way around.

shared_ptr gives you a copyable "handle" to a shared resource that can't itself be copied. Using shared_ptr with a type that doesn't perform its own cleanup when it is deleted isn't an optimal use.

If make your class' single responsibility to clean up this inherently non-copyable resource properly in its destructor, then you can use shared_ptr to provide shared ownership which is what its single responsibility should be. (I consider HANDLE to be non-copyable as if you try to make a simple copy of a HANDLE the copies cannot be treated as independent; the last copy must be correctly closed so the owners of copies would need to know about other copies in existence.)

class CWrapper
{
public:
    CWrapper()
    {
        // code to open handle
    }

    ~CWrapper()
    {
        // code to close handle
    }

private:
    // prevent copying
    CWrapper(const CWrapper&);
    CWrapper& operator=(const CWrapper&);

    HANDLE mHandle;
};

Now use shared_ptr<CWrapper> where you need to shared the handle, you can use a typedef if you think that this is too verbose.

A custom deleter is an overly complex solution, IMHO.

木落 2024-09-13 04:24:04

您不能调用成员函数,但可以使用作为全局函数的自定义删除器,如下所示:

void my_deleter(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, my_deleter); 

You can't call a member function but you can use a custom deleter that is a global function like so:

void my_deleter(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, my_deleter); 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文