一、拷贝构造

  如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都没有默认值,则此构造函数是拷贝构造函数。(《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++拷贝构造和移动构造的更多相关文章

  1. Effective C++_笔记_条款09_绝不在构造和析构过程中调用virtual函数

    (整理自Effctive C++,转载请注明.整理者:华科小涛@http://www.cnblogs.com/hust-ghtao/) 为方便采用书上的例子,先提出问题,在说解决方案. 1 问题 1: ...

  2. C++ 构造中调用构造

    //构造中调用构造 #define _CRT_SECURE_NO_WARNINGS #include<iostream> using namespace std; class Point{ ...

  3. 《Effective C++》读书笔记 被你忽略的关于构造析构赋值

    如果程序员没有定义,那么编译器会默认隐式为你创建一个copy构造函数,一个copy赋值操作符,一个析构函数.另外如果你没有声明任何构造函数,编译器会为你声明一个default构造函数. 但是只有当这些 ...

  4. C++深度解析教程学习笔记(6)对象的构造和销毁

    1. 对象的初始化 (1)从程序设计的角度看,对象只是变量,因此: ①在栈上创建对象时,成员变量初始化为随机值 ②在堆上创建对象时,成员变量初始化为随机值 ③在静态存储区创建对象时,成员变量初始化为 ...

  5. C#线程学习笔记五:线程同步--事件构造

    本笔记摘抄自:https://www.cnblogs.com/zhili/archive/2012/07/23/Event_Constructor.html,记录一下学习过程以备后续查用. 前面讲的线 ...

  6. STL——容器(Set & multiset)的默认构造 & 带参构造 & 对象的拷贝构造与赋值

    1. 默认构造 set<int> setInt;              //一个存放int的set容器. set<float> setFloat;          //一 ...

  7. C++ 笔记(二) —— 不要在构造和析构函数中调用虚函数

    ilocker:关注 Android 安全(新手) QQ: 2597294287 class Transaction { //所有交易的 base class public: Transaction( ...

  8. [DeeplearningAI笔记]卷积神经网络1.6-1.7构造多通道卷积神经网络

    4.1卷积神经网络 觉得有用的话,欢迎一起讨论相互学习~Follow Me 1.6多通道卷积 原理 对于一个多通道的卷积操作,可以将卷积核设置为一个立方体,则其从左上角开始向右移动然后向下移动,这里设 ...

  9. JavaScript模式读书笔记 文章3章 文字和构造

    1.对象字面量     -1.Javascript中所创建的自己定义对象在任务时候都是可变的.能够从一个空对象開始,依据须要添加函数.对象字面量模式能够使我们在创建对象的时候向其加入函数.       ...

随机推荐

  1. eclipse导入maven空项目,eclipse导入时不识别maven项目

    经常我们在网上下载的一些开源项目中,想要导入eclipse中,却发现eclipse不识别这个项目,这时候怎么办呢? 解决办法多种多样,我这里举例出最实用的2种: 1.在项目的根目录中加入.classp ...

  2. varchar、nvarchar

    Unicode字符集就是为了解决字符集这种不兼容的问题而产生的,它所有的字符都用两个字节表示,即英文字符也是用两个字节表示. NCHAR.NVARCHAR.NTEXT.这三种从名字上看比前面三种多了个 ...

  3. VBA学习资料分享-4

    工作中经常要从数据库把数据跑出来放到EXCEL上,才能进行下一步的操作,那么VBA如何结合SQL提取数据呢?答案就是ADO. 声明和实例变量 引用法——引用Microsoft ActiveX Data ...

  4. Go语言根据数据表自动生成model以及controller代码

    手写model的用法请参考: https://www.jianshu.com/p/f5784b8c00d0 这里仅说明自动生成model文件的过程 bee generate appcode -tabl ...

  5. Redis5.0.3单机版安装

    一.创建redis源码包存放目录 cd /usr/local/ mkdir redis 二.进入创建的目录,下载最新版Redis yum -y install wget wget http://dow ...

  6. MCU KEIL printf函数

    //加入以下代码,支持printf函数,而不需要选择use MicroLIB #if 1 #pragma import(__use_no_semihosting) //标准库需要的支持函数 struc ...

  7. redis——java访问redis

    1,使用jedis的java客户端来访问redis服务器,有点类似于通过jdbc访问mysql一样: 2,如果是spring集成时,可以使用spring data 来访问redis,spring da ...

  8. npm 安装指定版本的包

    使用 包名@版本号 指定, 例如,安装 Express 3.21.2, $ npm

  9. __builtin_ _Find_first()

    •int __builtin_ffs (unsigned int x) 返回x的最后一位1的是从后向前第几位,比如7368(1110011001000)返回4. •int __builtin_clz ...

  10. docker修改数据库密码

    运行mysql(--name 容器名称  -e MYSQL_ROOT_PASSWORD设置初始密码  -p 3307:3306  端口映射,主机端口3307) docker run --name my ...