c++ - 为什么禁用 CObject 的复制构造函数和赋值

标签 c++ mfc constructor

默认禁用MFC根对象CObject的拷贝构造函数和赋值。

The standard C++ default class copy constructor does a member-by-member copy. The presence of the private CObject copy constructor guarantees a compiler error message if the copy constructor of your class is needed but not available. You must therefore provide a copy constructor if your class requires this capability.

  • 在CObject的源码中,有一句注释:

Disable the copy constructor and assignment by default so you will get compiler errors instead of unexpected behaviour if you pass objects by value or assign objects.

我的问题是,这个 CObject 类的默认逐位复制构造函数有什么问题?在我看来,最好给我们一个默认的复制构造函数,如果需要的话我们可以提供一个(深复制)

最佳答案

默认的复制构造函数是逐个成员的,而不是按位的。

大多数 CObject 派生类包含 - 并直接管理 - 一些没有引用计数或类似机制的系统资源,因此做出选择时可能考虑了默认用例。

例如CGDIObject 大致是:

class CGDIObject : public CObject
{
    HGDIOBJ m_handle;

    CGDIObject() : m_handle(0) {}
    // derived classes provide a create, attach etc.
   ~CGDIObject() { DeleteObject(m_handle); } 
}

此处的默认复制构造函数是危险的(导致双重破坏),提供“正确”的复制构造函数出奇地困难且昂贵。

另一个原因可能是大多数 CObject 派生类都旨在进行变异,因此通过引用传递。缺少的复制构造函数将捕获意外的拷贝,这些拷贝会改变拷贝而不是传递的对象:

class CMyObject : public CObject
{
   public:
      AttachFoo(FooHandle foo) { ... }
      AddBar() { ... }
};

bool InitMySession(CMyObject & obj)
{
    obj.AttachFoo(CreateRawFoo());   
    obj.AddBar();
    obj.AddBar();
}

// ...
CMyObj mo;
InitMySession(mo);

省略“&”会让你的代码编译得很好,但会创建一个临时拷贝,修改它,然后删除它,而 mo 保持不变。

很多 API 都遵循这种模式,因为 MFC 不依赖异常进行错误处理(由于历史原因:并非所有目标编译器都很好地支持它们,并且 MFC 需要大量额外的资源处理,异常会变得很痛苦) .


我认为这些选择都不好,例如如果派生类的成员允许(并且大多数成员应该允许),应该允许派生类使用默认的复制构造函数。

不过,该决定符合 MFC 的“思维模式”,以及创建 MFC 时的要求/限制。

关于c++ - 为什么禁用 CObject 的复制构造函数和赋值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3085257/

相关文章:

c++ - 用户在“控制面板”->“区域和语言选项”中更改设置后修改主窗口的区域设置

C++ 什么是 "instantiated from here"错误?

c++ - Boost::spirit::qi 解析器不消耗整个字符串

c++ - 该标准是否保证添加构造函数不会改变大小?

javascript - 类型错误:日期不是构造函数

Scala 主构造函数及其生成的字段/属性

c++ - 检测 windows jpeg 图标

c++ - 默认 TreeView 项目高度

mfc - 如何停止 MFC/win32 控件重新绘制

c++ - MFC 事件处理程序