关于 "= default" 和 "= delete" 函数
在 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" 函数的更多相关文章
- c++11 类默认函数的控制:"=default" 和 "=delete"函数
c++11 类默认函数的控制:"=default" 和 "=delete"函数 #define _CRT_SECURE_NO_WARNINGS #include ...
- c++11 类默认函数的控制:"=default" 和 "=delete"函数 void fun() = default; void fun()=delete;
转自:lsgxeva #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #includ ...
- c++基础知识_c++11 类默认函数的控制:"=default" 和 "=delete"函数
#define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <vecto ...
- C++ default 和delete的新用法
C++中的默认函数与default和delete用法一. 类中的默认函数a.类中默认的成员函数1.默认构造函数2.默认析构函数3.拷贝构造函数4.拷贝赋值函数5.移动构造函数6.移动拷贝函数 b.类中 ...
- 重载operator new delete函数
可以重载global的operator new delete 函数,细节如下: MyNewDelete.h #pragma once #include <stdlib.h> #includ ...
- default和delete
在C++中,有四类特殊的成员函数,分别为:默认构造函数,默认析构函数,默认拷贝构造函数,默认赋值运算符.他们的作用为创建.初始化.销毁.拷贝对象. 虽然在类A中什么都没有定义,但是编译会通得过,因为编 ...
- C++中 destory() 和deallocate()以及delete函数的相关性和区别性
这里非常的绕口 需要仔细的来看看: destory(): 显示调用一个对象的析构函数 相当于释放一个对象需要释放的一些动态内存 为下次真正释放对象做准备 deallocate():真正的释放一个内存 ...
- STL--C++中 destory() 和deallocate()以及delete函数的相关性和区别性,destorydeallocate
这里非常的绕口 需要仔细的来看看: destory(): 显示调用一个对象的析构函数 相当于释放一个对象需要释放的一些动态内存 为下次真正释放对象做准备 deallocate():真正的释放一个内存 ...
- C++中 =default 和 =delete 使用
编译器默认为一个类生成的默认函数 默认构造函数 默认析构函数 默认拷贝构造函数 默认赋值函数 移动构造函数 移动拷贝函数 class DataOnly { public: DataOnly () // ...
- C++11的override、default和delete关键字
最近在参与组里的项目时接触了很多以前自己没太了解的C++语法(尤其是C++11以后出现的),今天给大家讲一下C++11新出的override和default关键字. override关键字主要在声明类 ...
随机推荐
- 技术干货 | Native 页面下如何实现导航栏的定制化开发?
简介: 通过不同实际场景的描述,供大家参考完成 Native 页面的定制化开发. 很多 mPaaS Coder 在接入 H5 容器后都会对容器的导航栏进行深度定制,本文旨在通过不同实际场景的描述 ...
- [FAQ] puppeteer 清空输入框的值 并 重新输入
一种方式是,清空输入框可以通过如下注入代码实现,但是可能存在 和页面本身的操作 存在优先级问题. await page.evaluate( () => document.getElementBy ...
- [Go] golang 执行 Linux 系统 command
执行系统 shell 命令示例: fileDir := "files/"out, err := exec.Command("sh", "-c" ...
- WPF 编写一个测试 WM_TOUCH 触摸消息延迟的应用
我听说在 Win10 到 Win11 的系统版本左右,微软加上了一大波触摸性能优化,准确来说是 HID 性能优化.我想测试一下在这些系统下,采用从 Windows 消息接收到 WM_TOUCH 触摸消 ...
- QT之Mysql驱动
错误现象 找不到Mysql驱动 QSqlDatabase: QMYSQL driver not loaded 一.驱动查看 在程序中直接打印QT Creator中现有的驱动,打印方式如下: qDebu ...
- vue-router设置页面切换滑动效果的方法及解决遇到的坑
先上gif:这里演示顺序是1232121 1.router.js中配置入口路由 { path: '/', redirect: '/index' } 2.main.js中new vu ...
- SAP集成技术(九)集成能力中心(ICC)
本文链接:https://www.cnblogs.com/hhelibeb/p/17867473.html 内容摘录自<SAP Interface Management Guide>. 定 ...
- Oracle中ALTER TABLE的五种用法(三)
首发微信公众号:SQL数据库运维 原文链接:https://mp.weixin.qq.com/s?__biz=MzI1NTQyNzg3MQ==&mid=2247485212&idx=1 ...
- C 语言编程 — 高级数据类型 — void 类型
目录 文章目录 目录 前文列表 void 类型 前文列表 <程序编译流程与 GCC 编译器> <C 语言编程 - 基本语法> <C 语言编程 - 基本数据类型> & ...
- angular打包优化
打包生产环境时需要的配置如下: 在angular.json里的"configurations"里配置: "configurations": { "pr ...