在 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. 【ClickHouse 技术系列】- ClickHouse 聚合函数和聚合状态

    简介:本文翻译自 Altinity 针对 ClickHouse 的系列技术文章.面向联机分析处理(OLAP)的开源分析引擎 ClickHouse,因其优良的查询性能,PB级的数据规模,简单的架构,被国 ...

  2. AI圈内卷?天池团聚请来专家集体“问诊”

    ​简介: 近期杭州云栖大会上出现了一个"数据博物馆",最吸引眼球的"展品",竟是行业大规模开源数据集.不仅数量多达上百个,还覆盖零售.文娱.工业.医疗.自然科学 ...

  3. [FE] 浅谈 Chakra UI 的现代化浅封装 - 语义化大行其道

      Web2.0 发展至今,网页元素越来越丰富和多样化,数据越来越多. 从需求上来说,也已经不再是展示简单个静态网页,高效的开发交互.打通后端数据,产生了 React 和 Vue 两个著名框架. Re ...

  4. dotnet 在析构函数调用 ThreadLocal 也许会抛出对方已释放

    我在不自量力做一个数组池,就是为了减少使用 System.Buffers.dll 程序集,然而在数组池里面,所用的 ThreadLocal 类型,在我对象析构函数进行归还数组时,抛出了无法访问已释放对 ...

  5. WPF 触摸底层 PenImc 是如何工作的

    在 WPF 里面有其他软件完全比不上的超快速的触摸,这个触摸是通过 PenImc 获取的.现在 WPF 开源了,本文就带大家来阅读触摸底层的代码,阅读本文需要一点 C# 和 C++ 基础 现在 WPF ...

  6. postman使用中问题汇总

    当用postman来通过接口造数据时,读取参数化文件中身份证字段的值读取错误. 参数文件如下 选择参数文件后预览的数据如下 身份证号码全部变成了0000结尾的 解决方案: 需要将身份证号码用引号引起来 ...

  7. docker-compose 安装 mysql:5.7.31

    目录 一.新建一个启动服务的目录 二.新建文件docker-compose.yml 三.新建角本文件 init-mysql.sh 四.实使化目录和配置文件 启动服务 登陆mysql 其它操作 参考文档 ...

  8. Gin框架

    目录 gin的参数获取 header参数 post Raw json 请求示例 gin的参数获取 package main import ( "fmt" "github. ...

  9. layui.js

    目录 用法: 1.在base.js里导入layui插件 2.在使用的html页面里引入 base.js lucky.js index.html 用法: 1.在base.js里导入layui插件 2.在 ...

  10. mysql命令最新

    查看授权 mysql> select user,host from mysql.user; +--------+------------+ | user | host | +--------+- ...