拷贝构造函数

c++11 右值引用、移动语义和完美转发

て烟熏妆下的殇ゞ 提交于 2020-02-14 03:19:49
c++11 右值引用、移动语义和完美转发 作者:StormZhu 链接:https://www.jianshu.com/p/d19fc8447eaa c++中引入了 右值引用 和 移动语义 ,可以避免无谓的复制,提高程序性能。有点难理解,于是花时间整理一下自己的理解。 左值、右值 C++ 中所有的值都必然属于左值、右值二者之一。左值是指表达式结束后依然存在的 持久化对象 ,右值是指表达式结束时就不再存在的 临时对象 。所有的具名变量或者对象都是左值,而右值不具名。很难得到左值和右值的真正定义,但是有一个可以区分左值和右值的便捷方法: 看能不能对表达式取地址,如果能,则为左值,否则为右值 。 看见书上又将右值分为将亡值和纯右值。纯右值就是 c++98 标准中右值的概念,如非引用返回的函数返回的临时变量值;一些运算表达式,如1+2产生的临时变量;不跟对象关联的字面量值,如2,'c',true,"hello";这些值都不能够被取地址。 而将亡值则是 c++11 新增的和右值引用相关的表达式,这样的表达式通常时将要移动的对象、 T&& 函数返回值、 std::move() 函数的返回值等, 不懂将亡值和纯右值的区别其实没关系,统一看作右值即可,不影响使用。 示例: int i=0;// i是左值, 0是右值 class A { public: int a; }; A getTemp() {

C++ 面向对象高级开发 -- string

﹥>﹥吖頭↗ 提交于 2020-02-14 01:29:42
1. Object Based(基于对象) vs. Object Oriented(面向对象) Object Based: 面对的是单一class的设计; Object Oriented:面对的是多重classes的设计,class 和 class 之间的关系。 classes 的两个经典分类: class without pointer members -- complex class with pointer members -- string 2. 设计 string   2.1 防卫式声明   2.2 Big Three 若类内有指针成员,则一定要重写 拷贝构造函数,赋值构造函数和析构函数,即Big Three,执行 深拷贝 操作。编译器默认生成的 拷贝构造函数和赋值构造函数 只会进行 浅拷贝 ! 由于未能确定string对象的大小,因此类内提供一个指针成员,指向动态内存。   2.3 ctor 和 dtor 注意!在析构函数中,调用 delete [] m_data; 释放内存。 在右下角的函数应用中,一旦离开作用域 {} , s1 和 s2 自动调用析构函数释放内存。由于 p 是动态分配的内存,其生命周期在整个程序运行周期内。p 要到程序结束运行后,由系统自动回收泄露的内存。   2.4 copy ctor 和 copy op= 拷贝构造函数 拷贝赋值函数 分3个步骤:

[转][c++11]我理解的右值引用、移动语义和完美转发

自作多情 提交于 2020-02-13 22:25:42
c++中引入了 右值引用 和 移动语义 ,可以避免无谓的复制,提高程序性能。有点难理解,于是花时间整理一下自己的理解。 左值、右值 C++ 中所有的值都必然属于左值、右值二者之一。左值是指表达式结束后依然存在的 持久化对象 ,右值是指表达式结束时就不再存在的 临时对象 。所有的具名变量或者对象都是左值,而右值不具名。很难得到左值和右值的真正定义,但是有一个可以区分左值和右值的便捷方法: 看能不能对表达式取地址,如果能,则为左值,否则为右值 。 看见书上又将右值分为将亡值和纯右值。纯右值就是 c++98 标准中右值的概念,如非引用返回的函数返回的临时变量值;一些运算表达式,如1+2产生的临时变量;不跟对象关联的字面量值,如2,'c',true,"hello";这些值都不能够被取地址。 而将亡值则是 c++11 新增的和右值引用相关的表达式,这样的表达式通常时将要移动的对象、 T&& 函数返回值、 std::move() 函数的返回值等, 不懂将亡值和纯右值的区别其实没关系,统一看作右值即可,不影响使用。 示例: int i=0;// i是左值, 0是右值 class A { public: int a; }; A getTemp() { return A(); } A a = getTemp(); // a是左值 getTemp()的返回值是右值(临时变量)   左值引用、右值引用

C++赋值函数详解

隐身守侯 提交于 2020-02-10 05:35:19
赋值函数 每个类只有一个赋值函数   由于并非所有的对象都会使用拷贝构造函数和赋值函数,程序员可能对这两个函数有些轻视。    1,如果不主动编写拷贝构造函数和赋值函数,编译器将以“位拷贝”的方式自动生成缺省的函数。倘若类中含有指针变量,那么这两个缺省的函数就隐含了错误。 以类String的两个对象a,b为例,假设a.m_data的内容为“hello”,b.m_data的内容为“world”。    现将a赋给b,缺省赋值函数的“位拷贝”意味着执行b.m_data = a.m_data。 这将造成三个错误: 一是b.m_data原有的内存没被释放,造成内存泄露; 二是b.m_data和a.m_data指向同一块内存,a或b任何一方变动都会影响另一方; 三是在对象被析构时,m_data被释放了两次。    2,拷贝构造函数和赋值函数非常容易混淆,常导致错写、错用。拷贝构造函数是在对象被创建时调用的,而赋值函数只能被已经存在了的对象调用。以下程序中,第三个语句和第四个语句很相似,你分得清楚哪个调用了拷贝构造函数,哪个调用了赋值函数吗?     String a(“hello”);    String b(“world”); String c = a;   // 调用了拷贝构造函数,最好写成 c(a);    c = b;      // 调用了赋值函数    本例中第三个语句的风格较差

赋值操作符和拷贝构造函数

南笙酒味 提交于 2020-02-08 11:25:33
今天在看一个消息结构的定义类时,有一个这样的接口 WF_MSG & operator=(const WF_MSG & _msg); 开始不是很明白,后来才知道这是赋值操作符,也通过这个深刻了解了赋值操作符,因为还定义了一个unsigned char * m_pMsgBuffer; /// 消息缓存指针 的指针,一般默认的赋值操作符是浅拷贝,而因为有消息缓存指针的变量,当这个消息类有两个对象时,如果一个消息赋值给另外一个消息,则会涉及到深拷贝的问题,所以要重新定义赋值操作符 这里有一博客,叙述的很详细,给大家分享下: 赋值运算符和复制构造函数都是用已存在的B对象来创建另一个对象A。不同之处在于:赋值运算符处理两个已有对象,即赋值前B应该是存在的;复制构造函数是生成一个全新的对象,即调用复制构造函数之前A不存在。 CTemp a(b); //复制构造函数,C++风格的初始化 CTemp a=b; //仍然是复制构造函数,不过这种风格只是为了与C兼容,与上面的效果一样 在这之前a不存在,或者说还未构造好。 CTemp a; a=b; //赋值运算符 在这之前a已经通过默认构造函数构造完成。 实例总结: 重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。 以下讨论中将用到的例子: class CExample { public: CExample(){pBuffer

C++拷贝构造函数和拷贝赋值运算符问题

こ雲淡風輕ζ 提交于 2020-02-07 16:05:27
为什么需要析构函数就几乎需要拷贝构造函数和拷贝赋值运算符?或者说拷贝构造函数和拷贝赋值运算符什么时候需要自己构造? 答: 当类内出现指针时,为了防止浅拷贝,即只对指针变量进行拷贝,而不对指针指向的对象也进行复制。自定义拷贝构造函数是为了防止析构函数多次delete同一个指针对象,而自定义拷贝赋值运算符是为了防止在赋值后一个指针所指向对象改变值后不改变另一个指针对象的值。 需要自定义拷贝构造函数示例(可注释掉拷贝构造函数,看注释前后输出发生了什么变化) // // Created by raysuner on 20-2-2. // #include <iostream> using namespace std; class A{ private: string *str; public: explicit A(const string &s){ cout << "构造函数" << endl; str = new string(s); } A(const A &a){ cout << "拷贝构造函数" << endl; this->str = new string(*a.str); } ~A() {delete str; cout << "析构函数" << endl;} void print(){ cout << *(this->str) << endl; } }; A f(A a){

c++深拷贝/浅拷贝

独自空忆成欢 提交于 2020-02-01 16:30:18
  拷贝构造函数,是一种特殊的构造函数,它由 编译器 调用来完成一些基于同一类的其他对象的构建及初始化。 其唯一的参数(对象的引用)是不可变的(const类型) 。此函数经常用在函数调用时用户定义类型的值传递及返回。拷贝构造函数要调用基类的拷贝构造函数和成员函数。 如果可以的话 ,它将用常量方式调用,另外,也可以用非常量方式调用。 一.什么时候对调用拷贝构造函数? 对象以值传递的方式传入函数参数 对象以值传递的方式从函数返回 对象需要通过另外一个对象进行初始化 二. 浅拷贝(位拷贝)和深拷贝   浅拷贝:也称位拷贝,编译器只是直接将指针的值拷贝过来,结果多个对象共用同一块内存,当一个对象将这块内存释放掉之后,另一些对象不知道该块空间已经还给了系统,以为还有效,所以在对这段内存进行操作的时候,发生了访问违规。   深拷贝: 如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配 防止默认拷贝发生   通过对对象复制的分析,我们发现对象的复制大多在进行“值传递”时发生,这里有一个小技巧可以防止按值传递——声明一个私有拷贝构造函数。甚至不必去定义这个拷贝构造函数,这样因为拷贝构造函数是私有的,如果用户试图按值传递或函数返回该类对象,将得到一个编译错误,从而可以避免按值传递或返回对象。 // 防止按值传递 class CExample { private: int a;

C++11 POD类型

邮差的信 提交于 2020-02-01 04:27:04
在C++中,声明自定义的类型之后,编译器会默认生成一些成员函数,这些函数被称为默认函数。其中包括 (1)构造函数 (2)拷贝构造函数 (3)拷贝赋值构造函数 (4)移动构造函数 (5)移动拷贝函数 (6)析构函数。 另外,编译器还会默认生成一些操作符函数,包括 (7)operator , (8)operator & (9)operator && (10)operator * (11)operator -> (12)operator ->* (13)operator new (14)operator delete 【1】显式缺省函数(=default) 但如果类的设计者又实现了这些函数的自定义版本后,编译器就不会去生成默认的版本。 有时候我们需要声明带参数的构造函数,此时就不会生成默认的构造函数,这样会导致类不再是POD类型(可参见随笔《 C++11 POD类型 》),从而影响类的优化: 1 #include <iostream> 2 using namespace std; 3 4 class Test 5 { 6 public: 7 Test(int i) : data(i) {} 8 9 private: 10 int data; 11 }; 12 13 int main() 14 { 15 std::cout << std::is_pod<Test>::value <<

C++对象构造语义学

|▌冷眼眸甩不掉的悲伤 提交于 2020-01-27 05:41:59
1 对象赋值及析构语义学 1.1 对象复制 当我们没有写默认的拷贝构造函数并且不满足编译器为我们默认合成构造函数的条件,当我们拷贝构造一个对象时,编译器也会进行一些特殊的复制处理 EG: #include<iostream> using namespace std; class A { public: int a; }; int main() { A a; a.a = 1; A a1 = a; cout << a1.a << endl; //打印1 return 0; } 1.2 对象析构 在以下两种情况下,如果我们自己没有写析构函数,编译器会为对象合成析构函数: 继承的基类中有析构函数,编译器会为派生类合成一个析构函数调用基类的析构函数 存在某一个成员变量类型为类A(类A有析构函数) 2 new与delete探究 2.1 new后面加不加括号的区别 EG: #include<iostream> using namespace std; class A { public: int a; }; class B { public: B() { } int b; }; int main() { //对于类A,我们没有自己提供构造函数 /* A a; cout << a.a << endl; //会报错,使用未初始化变量 A a1 = A(); cout << a1.a << endl;