在 C++ 11 中,"= default""= delete" 函数使我们能够显示指定成员函数是否自动生成。

其中,"= delete" 使我们能够避免所有函数 (特殊成员函数,普通成员函数和非成员函数) 参数中出现错误的类型提升 (导致非预期的函数调用)。

C++ 特殊成员函数:

即使用户不自定义,编译器也会自动生成的成员函数,包括

  • 构造函数
  • 拷贝构造函数
  • 拷贝赋值运算符
  • 移动构造函数
  • 移动赋值运算符
  • 析构函数

"= default" 函数

= default 可以用于任何特殊成员函数,比如显示指定特殊成员函数使用默认的函数实现,定义非公有的特殊成员函数,或者在某些情况下恢复特殊成员函数的自动生成。

示例:

struct widget
{
widget() = default; inline widget& operator=(const widget&);
}; inline widget& widget::operator=(const widget&) = default;

你可以在类的外部指定特殊成员函数为 = default,只要它是内联的。

由于默认特殊成员函数的性能优势,当需要默认行为时建议使用自动生成的特殊成员函数而不是使用空函数体。为此可以显示指定特殊成员函数为 = default 或者不声明它。

"= delete" 函数

定义函数(任何函数)为 = delete 防止其被定义和调用。

防止编译器生成你不需要的特殊成员函数。

= default不同,"= delete" 函数必须在函数声明的时候指定其为 = default, 而不能在之后重新声明其为 = default

示例:

struct widget
{
// deleted operator new prevents widget from being dynamically allocated.
void* operator new(std::size_t) = delete;
};

防止成员和非成员函数参数发生错误的类型提升导致非预期的函数调用。

示例:

// deleted overload prevents call through type promotion of float to double from succeeding.
void call_with_true_double_only(float) = delete;
void call_with_true_double_only(double param) { return; }

上面这个例子中,通过传递 float 类型参数来调用 call_with_true_double_only 会产生一个编译错误, 但是使用 int 类型参数则不会,int 类型的参数会被转换提升为 double 类型, 尽管这不是想要的结果。

为保证任何非 double 参数的调用能够产生编译错误,可以声明一个模板函数并指定其为 = delete

示例:

template < typename T >
void call_with_true_double_only(T) = delete; //prevent call through type promotion of any T to double from succeeding. void call_with_true_double_only(double param) { return; } // also define for const double, double&, etc. as needed.

"= default""= delete" 函数的优势

在 C++ 中,如果用户不自定义,编译器可以自动生成特殊成员函数。这对简单类型是方便的,但是复杂类型经常会自定义特殊成员函数,使用 = delete 可以防止这些特殊成员函数被自动创建。

在实践中:

  • 如果任何构造函数已经显示声明,那么默认构造函数就不会自动生成。
  • 如果虚析构函数已经显示声明,那么默认西沟函数就不会自动生成。
  • 如果移动构造函数或者移动赋值操作符已经显示声明,那么:
    • 拷贝构造函数就不会自动生成
    • 拷贝赋值运算符就不会自动生成
  • 如果拷贝构造函数,拷贝赋值操作符,移动构造函数或者移动赋值操作符已经显示声明,那么:
    • 移动构造函数就不会自动生成
    • 移动赋值运算符就不会自动生成

注意:

C++11 标准还规定了如下规则:

  • 如果拷贝构造函数或者析构函数被显示声明,那么拷贝赋值运算符就不会自动生成
  • 如果拷贝赋值运算符或者析构函数被显示声明,那么拷贝构造函数就不会自动生成

这两种情况下, Visual Studio 仍然会自动生成必要的函数,并不会产生告警。

在 C++11 之前,非拷贝类型的通用实现:

struct noncopyable
{
noncopyable() {}; private:
noncopyable(const noncopyable&);
noncopyable& operator=(const noncopyable&);
};

上述代码存在一些问题:

  • 拷贝构造函数声明为私有导致了默认构造函数无法自动生成,必须显示声明默认构造函数,即使他什么也不做。
  • 即使显示声明的默认构造函数声明也不做,编译器也将其认为是复杂的,其不如自动生产的默认构造函数来的高效,并且 noncopyable 也不会认为是 POD 类型。
  • 即使拷贝构造函数和拷贝赋值运算符被声明为私有的,成员函数和友元仍然能够调用他们,如果他们声明了但未定义,调用会产生链接错误。
  • 尽管这是通用的实现方式,但是其意图并不明显,除非你了解所有特殊成员函数自动生成的规则。

在 C++11 中, 非拷贝类型可以以更直接的方式实现从而解决了上述问题:

struct noncopyable
{
noncopyable() = default;
noncopyable(const noncopyable&) = delete;
noncopyable& operator=(const noncopyable&) = delete;
};

关于 "= default" 和 "= delete" 函数的更多相关文章

  1. c++11 类默认函数的控制:"=default" 和 "=delete"函数

    c++11 类默认函数的控制:"=default" 和 "=delete"函数 #define _CRT_SECURE_NO_WARNINGS #include ...

  2. c++11 类默认函数的控制:"=default" 和 "=delete"函数 void fun() = default; void fun()=delete;

    转自:lsgxeva #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #includ ...

  3. c++基础知识_c++11 类默认函数的控制:"=default" 和 "=delete"函数

    #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <vecto ...

  4. C++ default 和delete的新用法

    C++中的默认函数与default和delete用法一. 类中的默认函数a.类中默认的成员函数1.默认构造函数2.默认析构函数3.拷贝构造函数4.拷贝赋值函数5.移动构造函数6.移动拷贝函数 b.类中 ...

  5. 重载operator new delete函数

    可以重载global的operator new delete 函数,细节如下: MyNewDelete.h #pragma once #include <stdlib.h> #includ ...

  6. default和delete

    在C++中,有四类特殊的成员函数,分别为:默认构造函数,默认析构函数,默认拷贝构造函数,默认赋值运算符.他们的作用为创建.初始化.销毁.拷贝对象. 虽然在类A中什么都没有定义,但是编译会通得过,因为编 ...

  7. C++中 destory() 和deallocate()以及delete函数的相关性和区别性

    这里非常的绕口  需要仔细的来看看: destory(): 显示调用一个对象的析构函数 相当于释放一个对象需要释放的一些动态内存 为下次真正释放对象做准备 deallocate():真正的释放一个内存 ...

  8. STL--C++中 destory() 和deallocate()以及delete函数的相关性和区别性,destorydeallocate

    这里非常的绕口  需要仔细的来看看: destory(): 显示调用一个对象的析构函数 相当于释放一个对象需要释放的一些动态内存 为下次真正释放对象做准备 deallocate():真正的释放一个内存 ...

  9. C++中 =default 和 =delete 使用

    编译器默认为一个类生成的默认函数 默认构造函数 默认析构函数 默认拷贝构造函数 默认赋值函数 移动构造函数 移动拷贝函数 class DataOnly { public: DataOnly () // ...

  10. C++11的override、default和delete关键字

    最近在参与组里的项目时接触了很多以前自己没太了解的C++语法(尤其是C++11以后出现的),今天给大家讲一下C++11新出的override和default关键字. override关键字主要在声明类 ...

随机推荐

  1. [Py] Python 接口数据用 pandas 高效写入 csv

    通过 pandas 把 dict 数据封装,调用接口方法写入 csv 文件. import pandas as pd data = [{"name": "a"} ...

  2. dotnet 记 TaskCompletionSource 的 SetException 可能将异常记录到 UnobservedTaskException 的问题

    本文将记录 dotnet 的一个已知问题,且是设计如此的问题.假定有一个 TaskCompletionSource 对象,此对象的 Task 没有被任何地方引用等待.在 TaskCompletionS ...

  3. WPF 切换主题使用 luna 复古版本

    本文告诉大家如何在 WPF 里面使用 luna 等复古主题 今天在 lsj 说他准备优化 WPF 的程序集时,准备删除 luna 等程序集时,找到了一段有趣的注释,发现在 WPF 里面可以通过一些有趣 ...

  4. WPF 制作一个占用文件的测试工具

    我在开发软件进行测试时,需要测试拖入的文件被占用时软件的行为,于是就做了一个文件占用工具,此工具可以将某个文件进行占用,以及获取某个文件被哪个进程占用 先给大家看一下效果: 以上是拖入文件到灰色部分, ...

  5. dotnet C# 序列化 XML 时进行自动格式化

    默认的序列化对象为 XML 字符串时,是没有进行格式化的,也就是所有的内容都在相同的一行.本文告诉大家方法,在序列化对象时,转换的 XML 是格式化的.或者说拿到 XML 字符串,对这个 XML 字符 ...

  6. 优秀的 Modbus 从站(从机、服务端)仿真器、串口调试工具

    目录 优秀的 Modbus 从站(从机.服务端)仿真器.串口调试工具 主要功能 软件截图 优秀的 Modbus 从站(从机.服务端)仿真器.串口调试工具 官网下载地址:http://www.redis ...

  7. python01-03作业

    # 小球落地,一共运动了多少米 hight = 100 # 原始高度 distance = 0 # 和 for i in range(10): # 将 下落 高度加入到 和 中 distance += ...

  8. vue关于this.$refs.tabs.refreshs()刷新组件,缓存

    当更改了用户信息后,需要刷新页面或者组件. 1.当前组件刷新.定义一个请求用户信息的方法,在需要时调用: sessionStorage.setItem('userInfo',JSON.stringif ...

  9. Mybatis学习一(介绍/举例/优化)

    MyBatis介绍: MyBatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集.MyBatis ...

  10. ITIL4之四维模型

    ITIL4的一个核心概念.它定义了四个维度(图中的1~4),这四个维度旨在确保组织能够在多方面考虑其服务提供,从而更有效地创造和交付价值. 四维模型的整合流程 确立价值载体:明确信息服务提供商的价值主 ...