必须同时删除拷贝构造函数和拷贝赋值运算符,否则默认 operator= 仍存在,导致传值、容器插入等场景意外触发拷贝;正确做法是二者成对声明为 delete,且推荐置于 public 区域。
只声明 MyClass(const MyClass&) = delete; 无法阻止拷贝赋值,因为编译器仍会生成默认的 operator=。必须同时禁用拷贝构造和拷贝赋值,否则对象在传值、容器插入、隐式转换等场景下仍可能意外触发拷贝行为。
标准做法是显式删除拷贝构造函数和拷贝赋值运算符,且通常放在 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;
};
= default 给移动函数,编译器不会自动生成移动操作(因为存在用户声明的拷贝操作)protected 析构或确保派生类也禁用拷贝,否则子类可能绕过限制典型错误是只写 MyClass(const MyClass&) = delete;,然后尝试 a = b; —— 这会编译通过,因为默认赋值运算符仍存在。错误信息往往指向“use of deleted function”但发生在赋值处,容易让人误判问题位置。
operator= 调用点,而非类定义处static_assert(std::is_copy_constructible_v, "") 可在编译期验证是否真正禁用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 是最直接可控的方式,而继承基类适合多处复用;但无论哪种,漏掉拷贝赋值运算符都是高频疏忽点。