有时候,我们不能准许某个类进行复制,如std::mutex。以前的标准手法是将拷贝构造函数和复制赋值操作符声明为私有,且不给出实现,如此一来,外部代码无法复制,友元函数调用则链接错误(没有提供实现)。
C++11以后,标准委员会引入了通用的删除机制,只要声明函数用“=delete”修饰,函数就被声明为“删除”:
class no_copies
{
public:
no_copies(){}
no_copies(const no_copies&) = delete;
no_copies& operator = (const no_copies&) = delete;
};
新写法更清晰地表明了意图,且编译器能给出更具说明意义的错误提示,还会令链接时发生的错误提前至编译期。
若我们在实现某个类的时候,删除了拷贝构造和复制构造,又显式声明了移动构造和移动赋值函数,则便成了“移动型别”(move-only type),该特性与std::thread()和std::unique_lock<>相似。
只移动对象若要从左值移除,需要显式使用std::move()或static_cast<&&>表达意图:
move_only m1;
move_only m2(m1); //错误,m1的拷贝构造用“=delete”修饰
move_only m2(std::move(m1)); //正确,匹配移动构造函数
说明符“=delete”可以修饰任何函数,若某函数的重载声明为删除,却按普通方式参与重载解释(overload resolution)且被选定,则会导致编译错误。利用这一特性可以移除特定重载版本:假设某函数接收short类型参数,那它也允许传入int类型,即将int强制向下转换为short。若要严格杜绝这种转换,可以把重载声明为删除:
void func(short);
void func(int) = delete;
如果以int值作为func()的参数传入,会产生编译错误,需要显式转换为short:
func(39); //错误
func((short)39); //正确