创建一个只能直接构造和销毁,但不能被复制和移动的基类
在这里有一段ROS的ControllerBase基类实现的代码,代码如下所示:
class ControllerBase
{
public:ControllerBase() = default;virtual ~ControllerBase() = default;ControllerBase(const ControllerBase&) = delete;ControllerBase& operator=(const ControllerBase&) = delete;ControllerBase(ControllerBase&&) = delete;ControllerBase& operator=(ControllerBase&&) = delete;
1. 这段代码的完整语义
代码意图很明显:
ControllerBase
是一个抽象基类(base class),默认构造和析构是允许的,但 禁止复制 和 禁止移动。
这样做可以让该类的对象不可被直接拷贝或移动,常用于:
- 避免错误的拷贝(比如子类对象存在无法拷贝的资源)
- 避免多个对象持有同一资源
- 类似于单例模式或资源管理类这种需要明确的对象生命周期控制的场景
2. delete
关键字在这里的作用
C++11 引入了 = delete
语法,表示显式禁用某个函数。
当一个成员函数(包括构造函数、析构函数、赋值运算符等)被声明为 = delete
时:
- 编译器不会为它生成定义
- 如果代码里调用了这个函数,编译时会直接报错(而不是运行时报错)
- 用于表达该操作在语义上是禁止的
在你的类中:
ControllerBase(const ControllerBase&) = delete; // 删除拷贝构造函数
ControllerBase& operator=(const ControllerBase&) = delete; // 删除拷贝赋值运算符
ControllerBase(ControllerBase&&) = delete; // 删除移动构造函数
ControllerBase& operator=(ControllerBase&&) = delete; // 删除移动赋值运算符
结果:
-
ControllerBase
不能被用来拷贝构造:ControllerBase a; ControllerBase b = a; // ❌ 编译错误
-
不能被拷贝赋值:
ControllerBase a, b; a = b; // ❌ 编译错误
-
不能被移动构造:
ControllerBase a; ControllerBase b = std::move(a); // ❌ 编译错误
-
不能被移动赋值:
ControllerBase a, b; b = std::move(a); // ❌ 编译错误
这样就保证了 ControllerBase
只能用唯一的对象实例,禁止复制或移动。
3. ControllerBase&&
的含义(右值引用)
ControllerBase&&
是 右值引用(Right Value Reference)。
右值引用的主要用途是:
- 绑定到右值对象(临时对象、
std::move
后的对象) - 启用移动语义(避免不必要的深拷贝)
- 用于完美转发(
std::forward
)
例如:
ControllerBase&& r = ControllerBase(); // r 绑定到一个临时对象(右值)
在移动构造函数的上下文中:
ControllerBase(ControllerBase&& other);
表示接收一个来自右值的对象,这原本用于“偷取”它的资源(而不是拷贝),但你在这里加了 = delete
,
意味着即使传一个右值(例如 std::move(obj)
),也不允许移动构造。
4. 为什么要同时删除左值引用版本和右值引用版本的构造/赋值?
原因是:
- 如果你只删除了拷贝构造(
const ControllerBase&
),编译器会自动生成一个移动构造(ControllerBase&&
) - 如果你只删除了移动构造,编译器会用拷贝构造去替代
- 为了彻底禁止复制和移动,必须两个都 delete
这样即保证了:
- 不能
a = b;
- 不能
a = std::move(b);
- 不能
ControllerBase c = b;
- 不能
ControllerBase c = std::move(b);
5. 总结表格
成员函数 | 作用 | 在代码中的状态 |
---|---|---|
ControllerBase() | 默认构造函数 | 默认允许 |
~ControllerBase() | 析构函数 | 虚析构,允许 |
ControllerBase(const ControllerBase&) | 拷贝构造 | delete(禁止) |
ControllerBase& operator=(const ControllerBase&) | 拷贝赋值 | delete(禁止) |
ControllerBase(ControllerBase&&) | 移动构造 | delete(禁止) |
ControllerBase& operator=(ControllerBase&&) | 移动赋值 | delete(禁止) |
✅ 你这段代码的用途是:
创建一个只能直接构造和销毁,但不能被复制和移动的基类。