学而时习之,不亦说乎
Introduction
众所周知,C++类的特殊成员(构造函数、析构函数和赋值运算符),它们可以由编译器默认实现或由开发人员自己实现。但是,默认实现的规则有点复杂,可能会导致一些问题。 另一方面,我们有时希望防止对象复制、移动甚至构造对象。
这些都可以通过使用特殊的技巧来实现。在C++11的标准中,简化了许多。
类的特殊成员函数
特种成员函数
- 默认构造函数
- 析构函数
- 拷贝构造函数
- 拷贝赋值运算符
- 移动构造函数
- 移动赋值运算符
生成规则
- 如果存在用户自己的构造函数,则编译器不生成默认构造函数。
- 如果存在用户自己的虚拟析构函数,则默认情况下不生成默认构造函数。
- 如果存在用户定义的移动构造函数或移动赋值运算符,则默认情况下不会生成复制构造函数和复制赋值运算符。
还有其它一些规则,具体这些成员函数的生成规则建议参考<<effective modern c++>>一书条款17
实现机制
- 需要编译器
defalut函数,请使用=default。 只有具有默认值的特殊类成员函数才能使用这一用法,其它普通函数不可
// 类的特殊成员函数
struct Foo {
Foo() = default;
};
- 需要删除某个函数,请使用
=delete。 任何函数,包括非成员函数,都可以删除
// 类的特殊成员函数
struct Foo {
Foo(Foo const&) = delete;
};
// 普通函数
void func(int) = delete;
用途
- 实现不可复制且隐式不可移动的类,将复制构造函数和复制赋值运算符声明为已删除:
// 类的特殊成员函数
struct foo_not_copyable {
foo_not_copyable() = default;
foo_not_copyable(foo_not_copyable const &) = delete;
foo_not_copyable& operator=(foo_not_copyable const&) = delete;
};
- 实现不可复制但可移动的类,将复制操作声明为删除并且显式实现移动操作(并提供所需的任何其他构造函数):
struct data_wrapper {
public:
data_wrapper(Data *d = nullptr) : data(d) {}
~data_wrapper() { delete data; }
data_wrapper(data_wrapper const&) = delete;
data_wrapper& operator=(data_wrapper const&) = delete;
data_wrapper(data_wrapper&& other) : data(std::move(other.
data)) {
other.data = nullptr;
}
data_wrapper& operator=(data_wrapper&& other) {
if (this != std::addressof(other)) {
delete data;
data = std::move(other.data);
other.data = nullptr;
}
return *this;
}
private:
Data *data;
};
- 为确保函数仅使用特定类型形参,需要为函数提供删除的重载
template <typename T>
void run(T val) = delete;
void run(long val) {} // can only be called with long integers
run(42); // error, matches a deleted overload
run(42L); // OK, long integer arguments are allowed