在C++11中,如果想要禁止类的拷贝行为只需要把相应的函数设为 = delete即可,参见标准库的std::unique_ptr
unique_ptr (const unique_ptr&) = delete;
unique_ptr& operator= (const unique_ptr&) = delete;
对于普通的类,如果不去查看类的成员函数声明,我们是无法知道该类是否为不可复制的类型。在C++中,利用继承的技巧可以简单实现noncopyable类。
class noncopyable
{
public:
noncopyable(const noncopyable&) = delete;
void operator=(const noncopyable&) = delete;
protected:
noncopyable() = default;
~noncopyable() = default;
};
而在C++11之前想要如此实现是将对应的函数设置为private属性。那么我们就来详细了解一下这个=delete和=default有什么作用吧。
- 我们知道C++ 的一个类中默认有下列特殊成员函数,它们分别是:
- 默认构造函数
- 析构函数
- 拷贝构造函数
- 赋值运算符
- 取址运算符
- const取址运算符
前四个特殊函数负责实例化对象、销毁对象以及复制对象。
- 如果类中没有定义构造函数,则会生成一个默认构造函数。
#include <iostream> class A { public: void printHello() { std::cout << "hello"; } private: }; int main() { A a; a.printHello();//可以运行,表明a对象成功构造了 }
- 如果类中有自定义的构造函数,类就不会为其生成默认的构造函数了
#include <iostream> class A { public: A(int _a) { m_a = _a; } int getA() { return m_a; } private: int m_a; }; int main() { A a;//编译错误 没有此构造函数 A a(10);//正确 std::cout << a.getA(); }
- 倘若我们想使用默认构造函数,则必须显式地定义
class A { public: A(){} //显示定义 A(int _a) { m_a = _a; } private: int m_a; };
= default函数
- C++11 标准引入了一个新特性:"=default"函数。程序员只需在函数声明后加上“=default;”,就可将该函数声明为 "=default"函数,编译器将为其自动生成默认的函数定义体,提高代码的执行效率。
class A { public: A() = default; A(int _a){ m_a = _a;] int getA() {return m_a;} private: int m_a; };
- Tips:
- default函数仅适用于类的特殊成员函数,且该特殊成员函数没有默认参数。
class A { public: A() = default;//正确 A(int _a) = default;//错误,构造函数需要没有默认参数 int getA() = default;//错误,仅适用于类的特殊成员函数 }
- default函数既可以在类内声明类外定义,也可以在类内直接定义。
= delete函数
- =delete函数,编译器会对指定的函数禁用,从而避免了某些非法的函数调用或者类型转换,从而提高了代码的安全性。
- 编译器能自动生成类之间赋值、拷贝构造函数,在一定程度上减轻了代码量,但对于某些特定情况下,我们是不允许对象之间进行拷贝与赋值的,那么这时候,我们就需要考虑将拷贝、赋值构造函数禁用了:
class A
{
public:
A();
A(const A&) = delete; // 声明拷贝构造函数为 deleted 函数
A& operator = (const A &) = delete; // 声明拷贝赋值操作符为 deleted 函数
};
- Tips:
- 必须在函数第一次声明的时候将其声明为 = delete 函数,否则编译器会报错。
- = delete 函数特性可以作用于类的特殊成员函数、类的非特殊成员函数、普通成员函数
delete函数的其他作用
- = delete函数特性还可用于禁用类的某些转换构造函数,从而避免不期望的类型转换
class A
{
public:
A(double)
{
}
A(int) = delete;
};
- = delete 函数特性还可以用来禁用某些用户自定义的类的 new 操作符,从而避免在自由存储区创建类的对象
class A
{
public:
void *operator new(size_t) = delete;
void *operator new[](size_t) = delete;
};