0

让包装共享句柄的类可复制是否可以接受 C++ 风格?

我经常发现自己编写的类通过在类接口后面保存一个 shared_ptr 来隐藏一些粗糙的 C 库或 OS 资源的细节。例如

class window
{
public:
     window() : m_handle(OsCreateWindow(), OsDestroyWindow) {}

     void make_it_dance();
     void paint_it_red();
private:
     shared_ptr<OS_WINDOW_HANDLE> m_handle;
}

因为类是可复制的并且shared_ptr可以完成繁重的工作,所以实例可以随意传递,没有任何东西泄漏或被破坏两次。所以,从技术上讲,一切都很好。我多年来一直这样做。

但最近我开始怀疑这是否真的是很好的风格。毕竟,当类实例复制时,句柄末尾的对象并没有被复制。让所有这些类都不可复制,让用户非常清楚他们正在处理对同一对象的引用会更好吗?现代 C++ 非常重视“基于价值”,而在实例之间共享后端资源似乎违背了这一原则。

然而,结果是我的大部分代码都会处理指针,即使它们是智能指针。这似乎是倒退了一步。

4

4 回答 4

2

我想我明白你的困境是什么。我有一个相当愚蠢的建议。

由于您的问题不是功能性的,而是期望复制您的window实例会创建,如果您将这样的类命名为 this awindow_handle而不是 会更好window吗?

这意味着这只是某个窗口的句柄,复制它不会创建新窗口或类似的东西,它只是复制一个句柄。

需要强调的是,我建议您保留您的设计(这对我来说似乎是一个不错的设计,并且似乎对您有用)并且只需更改您的命名以改变对更高层代码的期望。

于 2013-06-26T23:42:31.447 回答
0

就个人而言,我不允许复制并同意使用共享指针是一种倒退。我还要补充一点,每个“Window”实例都应该包含一个唯一的 OS_WINDOW_HANDLE。

您还可以使用 MFC 方法在对象之间传递句柄。MFC 使用 Attach 和 Detach 方法,如下所示...

class Window
{
public:
  void Attach (OS_WINDOW_HANDLE handle)
  {
    ASSERT(NULL == m_handle);  // or you could destroy the existing handle
    m_handle = handle;
  }

  OS_WINDOW_HANDLE Detach()
  {
    OS_WINDOW_HANDLE retVal = m_handle;
    m_handle = NULL;
    return retVal;
  }

private:
  // disable copy constructor and assignment
  Window(const Window&);
  Window& operator=(const Window&);
};
于 2013-06-26T23:31:38.413 回答
0

一个可能的答案(以及引发该问题的情况)是,静默共享支持对象会使该类的用户难以确保该对象在特定点“死”。例如,对象可能是网络连接,出于安全原因,用户需要知道连接已关闭。

如果连接包装器是可复制的并在实例之间共享连接,那么用户必须研究实例可能流过的路径,以确保副本不能保存在意外的地方并保持连接打开。

另一方面,如果包装器是不可复制的,则只有一个实例可以确保已死。引用可能仍然被分发,但是一旦原始包装器死掉,用户可以确定支持对象也死了。

如果用户想要共享副本,他们总是可以使用 shared_ptr 再次恢复它。但这一次,决定权在他们手中。

于 2013-06-26T23:43:41.653 回答
0

如果句柄指向的资源不需要复制(浅拷贝),请使用std::shared_ptr. 如果确实需要复制资源(深拷贝),您应该使用std::unique_ptr. 如果不需要复制,请使用std::unique_ptr.

于 2013-06-26T23:34:59.837 回答