Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++;样式:可复制句柄包装类 允许共享包装句柄的类是可复制的C++风格吗?< /P>_C++_Coding Style_Shared Ptr_Raii_Idioms - Fatal编程技术网

C++;样式:可复制句柄包装类 允许共享包装句柄的类是可复制的C++风格吗?< /P>

C++;样式:可复制句柄包装类 允许共享包装句柄的类是可复制的C++风格吗?< /P>,c++,coding-style,shared-ptr,raii,idioms,C++,Coding Style,Shared Ptr,Raii,Idioms,我经常发现自己编写的类通过在类接口后面保存一个共享的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;

我经常发现自己编写的类通过在类接口后面保存一个共享的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;
}
类窗口
{
公众:
window():m_句柄(OsCreateWindow(),OsDestroyWindow){}
虚空让它跳舞();
将其涂成红色();
私人:
共享的ptr m_句柄;
}
因为类是可复制的,而且
shared_ptr
做了艰苦的工作,所以实例可以随意地传递,没有任何东西泄漏或被破坏两次。因此,从技术上讲,一切都是好的。我已经做了很多年了

但最近我开始怀疑这是否真的是一种好的风格。毕竟,当类实例被复制时,句柄末尾的对象没有被复制。让所有这些类都不可复制,让用户清楚地知道它们处理的是对同一对象的引用,这样会更好吗?现代C++使其成为“基于价值的”,在实例之间共享后端资源似乎违背了这个原则。
然而,结果是,我的代码中有很大一部分将处理指针,即使它们是智能指针。这似乎是一种倒退。

就个人而言,我不允许复制,并且同意使用共享指针是一种倒退。我还要补充的是,每个“窗口”实例都应该包含一个唯一的OS\U窗口\U句柄

您还可以使用MFC方法在对象之间传递句柄。MFC使用如下的附加和分离方法

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&);
};

如果句柄指向的资源不需要复制(浅拷贝),请使用
std::shared\u ptr
。如果资源确实需要复制(深度复制),则应使用
std::unique\u ptr
。如果不需要复制,请使用
std::unique\u ptr

我想我理解您的困境所在。我有一个相当愚蠢的建议

由于您的问题不是功能性的,而是希望复制您的
窗口
实例会创建一个类,因此如果将此类命名为
窗口句柄
而不是
窗口
,会不会更好

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

要强调的是,我建议您保留您的设计(对我来说这似乎是一个不错的设计,而且似乎适合您),只需更改您的命名即可更改对更高层次代码的期望。

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

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

另一方面,如果包装器是不可复制的,那么只有一个实例可以确保它是死的。引用仍然可以分发,但一旦原始包装器死亡,用户就可以确保支持对象也死亡


如果用户想要共享副本,他们可以使用共享ptr再次恢复该副本。但这一次是他们的决定。

您是否建议将这些作为实现我所描述的不同行为的方法?我知道如何获得这些行为。问题是哪些行为更好。这不是一个愚蠢的建议。但我对“基于价值的C++”的含义感兴趣,它希望复制的实例彼此独立。起初我认为这个窗口处理方法只会并行<代码> SyddYPPT/<代码>,它具有值语义(一个拷贝上的操作不会明显影响其他的行为)。但后来我意识到这不适用于
window\u handle
,因为它有完整的窗口界面,非常量操作肯定会影响其他人的行为。解决方案是为可复制的
window\u句柄
提供一个访问器方法,返回一个不可复制的
窗口
,后者拥有接口的其余部分。但是到那时,我基本上已经有了一个
共享的\u ptr
类型定义。@thehouse:我相信那些比我更有知识和经验的人能够在这方面帮助你。但在我看来,handle/smart-pointer/ID类和对象并没有什么问题。毕竟,<代码> SydDypTr>代码>正是这样一个类(它的复制实例不是相互独立的),而你的类只封装了一个<代码> SydDypTr> /Calp>。它们与您的情况类似,因为它们是指向容器的轻型对象。每个人都知道可以通过迭代器更改容器(更改元素、删除元素和重新分配整个内容等)。它被理解和接受。同样,
shared_ptr
也是如此。您可以通过
共享\u ptr
更改底层对象,每个人都理解并接受这一点。因此,虽然你关于值语义的观点是正确的,但它们不是通用的;标准库本身包含一些例外。如果你阅读我的另一个回复,你会发现我也有同样的回答,但事实并非如此。一个
shared_ptr
和它的副本不能改变它的方法的可观察行为(好的,除了两个,它们揭示了潜在的引用计数,所以我猜它不是100%)。共享指针对象可以改变其行为,但这是
sh中的一个变化