3

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

想象一下下面的代码:

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 参数创建关闭(不理想)。无论哪种方式,我都会收到编译器错误“术语不会评估为采用 0 个参数的函数”。这是因为隐含的 this 指针吗?我该如何解决?如何从共享指针调用成员函数?

4

5 回答 5

6

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

void my_deleter(Foo *ptr)
{
 delete ptr;
 std::cout<< "using custom deleter" <<std::endl;
}
shared_ptr<Foo> pf (new Foo, my_deleter); 
于 2010-06-20T12:20:44.907 回答
5

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

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<CWrapper>在需要共享句柄的地方使用,如果您认为这太冗长,可以使用 typedef。

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

于 2010-06-20T12:50:58.683 回答
5

如果您需要从内部访问非静态成员,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();

最后一个过期的包装器将破坏句柄,该句柄在所有包装器之间显式共享。

于 2010-06-20T13:56:56.160 回答
3

我还没有测试过,但是根据 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)); 
于 2010-06-20T12:27:16.010 回答
0

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

于 2010-06-20T12:21:19.710 回答