贝利信息

C++中如何实现一个不可拷贝的类?(将拷贝构造函数设为delete)

日期:2026-01-15 00:00 / 作者:裘德小鎮的故事
必须同时删除拷贝构造函数和拷贝赋值运算符,否则默认 operator= 仍存在,导致传值、容器插入等场景意外触发拷贝;正确做法是二者成对声明为 delete,且推荐置于 public 区域。

为什么直接 delete 拷贝构造函数还不够

只声明 MyClass(const MyClass&) = delete; 无法阻止拷贝赋值,因为编译器仍会生成默认的 operator=。必须同时禁用拷贝构造和拷贝赋值,否则对象在传值、容器插入、隐式转换等场景下仍可能意外触发拷贝行为。

正确写法:两个 delete 必须成对出现

标准做法是显式删除拷贝构造函数和拷贝赋值运算符,且通常放在 private 区域(C++11 前)或 public 区域(C++11 起推荐),后者更清晰、错误提示更直接。

class NonCopyable {
public:
    NonCopyable() = default;
    NonCopyable(con

st NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; // 移动语义可选,但若保留需显式定义 NonCopyable(NonCopyable&&) noexcept = default; NonCopyable& operator=(NonCopyable&&) noexcept = default; };

常见误用:只删构造函数却忘了 operator=

典型错误是只写 MyClass(const MyClass&) = delete;,然后尝试 a = b; —— 这会编译通过,因为默认赋值运算符仍存在。错误信息往往指向“use of deleted function”但发生在赋值处,容易让人误判问题位置。

比手动 delete 更省事的方式:继承 std::noncopyable

Boost 提供了 boost::noncopyable,C++ 标准库虽无等价物,但可轻松手写一个空基类,让所有需要不可拷贝的类统一继承:

struct noncopyable {
protected:
    noncopyable() = default;
    ~noncopyable() = default;
    noncopyable(const noncopyable&) = delete;
    noncopyable& operator=(const noncopyable&) = delete;
};

继承它即可:class Logger : private noncopyable { ... };。注意用 private 继承,避免接口污染;若需移动语义,仍需在派生类中显式声明移动函数。

手动 delete 是最直接可控的方式,而继承基类适合多处复用;但无论哪种,漏掉拷贝赋值运算符都是高频疏忽点。