让包装共享句柄的类可以复制是否可以接受C ++样式?
我经常发现自己编写的类通过在类接口后面保存shared_ptr来隐藏一些粗略的C库或OS资源的细节。 E.g。
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 ++大量存在“基于价值”,并且在实例之间共享后端资源似乎违背了这一原则。
然而,结果是我的大部分代码都会处理指针,即使它们是智能指针。这似乎是倒退了一步。
答案 0 :(得分:2)
我想我明白你的困境是什么。我有一个相当愚蠢的建议。
由于您的问题无法正常运行,而是期望复制window
实例,因此如果您将此类命名为window_handle
而不是{{1},那会不会更好}}?
这意味着它只是一个窗口的句柄,复制它不会创建一个新的窗口或类似的东西,它只是复制一个句柄。
要强调的是,我建议您保留您的设计(这对我来说似乎很好,似乎正在为您工作)并且只需更改命名以更改代码的更高层的期望。
答案 1 :(得分: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&);
};
答案 2 :(得分:0)
如果句柄指向的资源不需要复制(浅拷贝),请使用std::shared_ptr
。如果资源 需要复制(深层复制),则应使用std::unique_ptr
。如果不需要复制,请使用std::unique_ptr
。
答案 3 :(得分:0)
一个可能的答案(以及提示问题的情况)是静默共享支持对象使得类的用户很难确保对象在特定点“死”。 例如,对象可能是网络连接,并且出于安全原因,用户需要知道连接已被关闭。
如果连接包装器是可复制的并且共享实例之间的连接,那么用户必须研究实例可能流过的路径,以确保副本无法保存在意外的位置并保持连接打开。
另一方面,如果包装器是不可复制的,那么只有一个实例可以确保死亡。引用仍然可以分发,但是一旦原始包装器死掉,用户就可以确定后备对象也已经死了。
如果用户想要拥有共享副本,他们可以再次使用shared_ptr恢复该副本。但这次决定是他们的。