[笔记]C++拷贝构造和移动构造
一、拷贝构造
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都没有默认值,则此构造函数是拷贝构造函数。(《C++Primer,第五版》)
class Foo
{
public :
Foo();
Foo(const Foo&); //拷贝构造函数
Foo& operator=(const Foo&); //拷贝赋值运算符
};
类的成员中有指针时,使用深拷贝。
#include <iostream>
using namespace std; class Foo
{
public:
Foo()
{
pInt = new int;
*pInt = ;
}
Foo(const Foo&)= default; //拷贝构造函数
Foo& operator=(const Foo&) = default; //拷贝赋值运算符 int* pInt;
}; //浅拷贝,foo1和foo2中的pInt指向同一块内存地址
Foo foo1;
Foo foo2(foo1); //深拷贝
class Cop
{
public:
Cop()
{
pInt = new int;
*pInt = ;
}
Cop(const Cop& cop)
{
pInt = new int;
*pInt = *(cop.pInt);
}
int* pInt;
};
//深拷贝,cop1和cop2中pInt指向不同内存
Cop cop1;
Cop cop2(cop1);
二、移动构造
在某些情况下(函数返回对象引用),对象拷贝后立即就被消耗了。拷贝构造就回造成性能上的浪费,而且深拷贝也会造成浪费。移动构造可以避免这种情况的发生。
为了支持移动构造,C++11引入了右值引用。
右值引用:必须绑定到右值的引用,通过&&来获得右值引用,类似左值引用(常规引用),右值应用也是一块内存的别名。
右值:字面常量、在表达式求值过程中临时创建的对象,这些使用过后就被销毁的资源。不同于左值的持久状态。
因此,右值引用只能绑定到将要被销毁的对象上,左值引用只能绑定到持久的对象上。
//例子来源于 《C++primer 第五版》 int i = ;
int& r = i; //正确,i是左值
int&& rr = i; //错误
int& r2 = i * ; //错误,i*42是右值,用完即销毁
const int& r3 = i * ; //正确,隐式转换为左值后,r3引用
int&& rr2 = i * ; //正确,绑定右值
int&& rr1 = 42; //正确,字面常量是右值
int&& rr2 = rr1; //错误,rr1左值
变量都是左值,因此无法将右值引用绑定到一个右值引用类型的变量上。
如果要将右值引用绑定到左值上,可以通过move函数来获得左值的右值引用类型。对一个左值调用move函数后,除了对该左值赋值和销毁外,不再使用它。
int i = ;
int&& rr = move(i); //i和rr引用同一块内存 i = ; cout << i << endl;
cout << rr << endl;
移动构造函数依靠右值引用特性来将来改变内存的管理者,而不同于拷贝构造对内存进行拷贝。
移动构造:第一个参数是该类类型的一个右值引用,且任何额外的参数都必须有默认实参。使用移动构造函数必须确保销毁移后源对象是无害的(不会重复释放同一块内存)。
Cop(Cop&& cop) noexcept : pInt(cop.pInt)
{
cout << "this is &&" << endl;
cop.pInt = NULL;
}
Cop& operator=(Cop&& cop) noexcept
{
if ( this == &cop ) return *this;
cout << "this is && =" << endl;
delete pInt;
pInt = cop.pInt;
cop.pInt = NULL; } Cop retCop()
{
Cop cop3;
*cop3.pInt = ;
return cop3;
} //调用移动赋值运算符,cop3中pInt接管retCop返回对象中的pInt指向内存
Cop cop3 = retCop();
noexcept承诺函数不抛出异常,标准库对这个函数不做额外处理。
[笔记]C++拷贝构造和移动构造的更多相关文章
- Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数
(整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: ...
- C++ 构造中调用构造
//构造中调用构造 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Point{ ...
- 《Effective C++》读书笔记 被你忽略的关于构造析构赋值
如果程序员没有定义,那么编译器会默认隐式为你创建一个copy构造函数,一个copy赋值操作符,一个析构函数.另外如果你没有声明任何构造函数,编译器会为你声明一个default构造函数. 但是只有当这些 ...
- C++深度解析教程学习笔记(6)对象的构造和销毁
1. 对象的初始化 (1)从程序设计的角度看,对象只是变量,因此: ①在栈上创建对象时,成员变量初始化为随机值 ②在堆上创建对象时,成员变量初始化为随机值 ③在静态存储区创建对象时,成员变量初始化为 ...
- C#线程学习笔记五:线程同步--事件构造
本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...
- STL——容器(Set & multiset)的默认构造 & 带参构造 & 对象的拷贝构造与赋值
1. 默认构造 set<int> setInt; //一个存放int的set容器. set<float> setFloat; //一 ...
- C++ 笔记(二) —— 不要在构造和析构函数中调用虚函数
ilocker:关注 Android 安全(新手) QQ: 2597294287 class Transaction { //所有交易的 base class public: Transaction( ...
- [DeeplearningAI笔记]卷积神经网络1.6-1.7构造多通道卷积神经网络
4.1卷积神经网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.6多通道卷积 原理 对于一个多通道的卷积操作,可以将卷积核设置为一个立方体,则其从左上角开始向右移动然后向下移动,这里设 ...
- JavaScript模式读书笔记 文章3章 文字和构造
1.对象字面量 -1.Javascript中所创建的自己定义对象在任务时候都是可变的.能够从一个空对象開始,依据须要添加函数.对象字面量模式能够使我们在创建对象的时候向其加入函数. ...
随机推荐
- eclipse导入maven空项目,eclipse导入时不识别maven项目
经常我们在网上下载的一些开源项目中,想要导入eclipse中,却发现eclipse不识别这个项目,这时候怎么办呢? 解决办法多种多样,我这里举例出最实用的2种: 1.在项目的根目录中加入.classp ...
- varchar、nvarchar
Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示. NCHAR.NVARCHAR.NTEXT.这三种从名字上看比前面三种多了个 ...
- VBA学习资料分享-4
工作中经常要从数据库把数据跑出来放到EXCEL上,才能进行下一步的操作,那么VBA如何结合SQL提取数据呢?答案就是ADO. 声明和实例变量 引用法——引用Microsoft ActiveX Data ...
- Go语言根据数据表自动生成model以及controller代码
手写model的用法请参考: https://www.jianshu.com/p/f5784b8c00d0 这里仅说明自动生成model文件的过程 bee generate appcode -tabl ...
- Redis5.0.3单机版安装
一.创建redis源码包存放目录 cd /usr/local/ mkdir redis 二.进入创建的目录,下载最新版Redis yum -y install wget wget http://dow ...
- MCU KEIL printf函数
//加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struc ...
- redis——java访问redis
1,使用jedis的java客户端来访问redis服务器,有点类似于通过jdbc访问mysql一样: 2,如果是spring集成时,可以使用spring data 来访问redis,spring da ...
- npm 安装指定版本的包
使用 包名@版本号 指定, 例如,安装 Express 3.21.2, $ npm
- __builtin_ _Find_first()
•int __builtin_ffs (unsigned int x) 返回x的最后一位1的是从后向前第几位,比如7368(1110011001000)返回4. •int __builtin_clz ...
- docker修改数据库密码
运行mysql(--name 容器名称 -e MYSQL_ROOT_PASSWORD设置初始密码 -p 3307:3306 端口映射,主机端口3307) docker run --name my ...