1、The Copy Constructor

What is a copy constructor? When is it used?

A copy constructor is a constructor which first parameter is a reference to the class type and any additional parameters have

default values.

When copy initialization happens and that copy initialization requires either the copy constructor or the move constructor

  • Define variables using an =
  • Pass an object as an argument to a parameter of non-reference type
  • Return an object from a function that has a non-reference return type
  • Brace initialize the elements in an array or the members of an aggregate class
  • Some class types also use copy initialization for the objects they allocate.

Assuming Point is a class type with a public copy constructor, identify each use of the copy constructor in this program fragment:

Point global;
Point foo_bar(Point arg) // 1
{Point local = arg, *heap = new Point(global); // 2, 3*heap = local;Point pa[ 4 ] = { local, *heap }; // 4, 5return *heap; // 6
}

2、The Copy-Assignment Operator

What is a copy-assignment operator? When is this operator used? What does the synthesized copy-assignment operator do? When is it synthesized?

The copy-assignment operator is function named operator=.This operator is used when assignment occurred.The synthesized copy-assignment operator assigns each non-static member of the right-hand object to corresponding member of the left-hand object using the copy-assignment operator for the type of that member.It is synthesized when the class does not define its own

3、The Destructor

What is a destructor? What does the synthesized destructor do? When is a destructor synthesized?

The destructor is a member function with the name of the class prefixed by a tilde(~).As with the copy constructor and the copy-assignment operator, for some classes, the synthesized destructor is defined to disallow objects of the type from being destroyed. Otherwise, the synthesized destructor has an empty function body.

The compiler defines a synthesized destructor for any class that does not define its own destructor.Just as a constructor has an initialization part and a function body (§ 7.5.1, p. 288), a destructor has a function body and a destruction part. In a constructor, members are initialized before the function body is executed, and members are initialized in the same order as they appear in the class. In a destructor,the function body is executed first and then the members are destroyed. Members are destroyed in reverse orderfrom the order in which they were initialized

In a destructor, there is nothing akin to the constructor initializer list to control how members are destroyed; the destruction part is implicit. What happens when a member is destroyed depends on the type of the member.Members of class type are destroyed by running the member’s own destructor. The built-in types do not have destructors, so nothing is done to destroy members of built-in typenote: The destructor is not run when a reference or a pointer to an object goes out of scope.

{// new scope// p and p2 point to dynamically allocated objectsSales_data *p = new Sales_data;        // p is a built-in pointerauto p2 = make_shared<Sales_data>();   // p2 is a shared_ptrSales_data item(*p);                   // copy constructor copies *p into itemvector<Sales_data> vec;                // local objectvec.push_back(*p2);                    // copies the object to which p2 pointsdelete p;                              // destructor called on the object pointed to by p
}// exit local scope; destructor called on item, p2, and vec// destroying p2 decrements its use count; if the count goes to 0, the object is freed// destroying vec destroys the elements in vec
#include <iostream>
#include <vector>
#include <initializer_list>struct X {X() { std::cout << "X()" << std::endl; }                    //1X(const X&) { std::cout << "X(const X&)" << std::endl; }    //2X& operator=(const X&)                                      //3{std::cout << "X& operator=(const X&)" << std::endl;return *this;}~X() { std::cout << "~X()" << std::endl; }                  //4
};void f(const X& rx, X x)    // 2
{std::vector<X> vec;     //omit skip the constructorvec.reserve(2);         //omit skip the constructorX y = x;  //2y=rx;     //3vec.push_back(rx);        //2vec.push_back(x);         //2
}// destroy y, vec(twice), x  //4 timesint main()
{X* px = new X;   //1f(*px, *px);delete px;       //4return 0;
}

 The Rule of Three/Five

Classes That Need Destructors Need Copy and Assignment

Classes That Need Copy Need Assignment, and Vice Versa


Preventing Copies

The Destructor Should Not be a Deleted Member

reason:It is not possible to define an object or delete a pointer to a dynamically allocated object of a type with a deleted destructor

The Copy-Control Members May Be Synthesized as Deleted

1、The synthesized destructor is defined as deleted if the class has amember whose own destructor is deleted or is inaccessible (e.g., private).
2、The synthesized copy constructor is defined as deleted if the class has a member whose own copy constructor is deleted or inaccessible.It is also deleted if the class has a member with a deleted or inaccessible destructor.

3、The synthesized copy-assignment operator is defined as deleted if a member
has a deleted or inaccessible copy-assignment operator, or if the class has a
const or reference member.
4、The synthesized default constructoris defined as deleted if the class has a member with a deleted or inaccessible destructor;or has a reference member that does not have an in-class initializer (§ 2.6.1, p. 73);or has a const member whose type does not explicitly define a default constructor and that member does not have an in-class initializer

note:In essence, the copy-control members are synthesized as deleted when it is impossible to copy, assign, or destroy a member of the class

Swap 

string *temp = v1.ps; // make a temporary copy of the pointer in v1.ps
v1.ps = v2.ps;        // assign the pointer in v2.ps to v1.ps
v2.ps = temp;         // assign the saved pointer in v1.ps to v2.ps

instead

void swap(HasPtr &lhs, HasPtr &rhs)
{using std::swap;swap(lhs.ps, rhs.ps); // swap the pointers, not the string dataswap(lhs.i, rhs.i); // swap the int members
}

swap Functions Should Call swap, Not std::swap

void swap(Foo &lhs, Foo &rhs)
{using std::swap;swap(lhs.h, rhs.h); // uses the HasPtr version of swap// swap other members of type Foo
}

Using swap in Assignment Operators 

Assignment operators that use copy and swap are automatically exception safe and correctly handle self-assignment

#include <string>
#include <iostream>class HasPtr
{
public:friend void swap(HasPtr&, HasPtr&);friend bool operator<(const HasPtr &lhs, const HasPtr &rhs);HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { }HasPtr& operator=(HasPtr tmp) {this->swap(tmp);return *this;}~HasPtr() {delete ps;}void swap(HasPtr &rhs) {using std::swap;swap(ps, rhs.ps);swap(i, rhs.i);std::cout << "call swap(HasPtr &rhs)" << std::endl;}void show() const{ std::cout << *ps << std::endl; }
private:std::string *ps;int i;
};void swap(HasPtr& lhs, HasPtr& rhs)
{lhs.swap(rhs);
}bool operator<(const HasPtr &lhs, const HasPtr &rhs)
{return *lhs.ps < *rhs.ps;
}

Essentially, the specific avoiding memory allocation is the reason why it improve performance. As for the pointerlike version, no dynamic memory allocation anyway. Thus, a specific version for the valuelike will not improve the performance.

Swap 

string *temp = v1.ps; // make a temporary copy of the pointer in v1.ps
v1.ps = v2.ps;        // assign the pointer in v2.ps to v1.ps
v2.ps = temp;         // assign the saved pointer in v1.ps to v2.ps

instead

void swap(HasPtr &lhs, HasPtr &rhs)
{using std::swap;swap(lhs.ps, rhs.ps); // swap the pointers, not the string dataswap(lhs.i, rhs.i);   // swap the int members
}

swap Functions Should Call swap, Not std::swap

void swap(Foo &lhs, Foo &rhs)
{using std::swap;swap(lhs.h, rhs.h); // uses the HasPtr version of swap// swap other members of type Foo
}


Using swap in Assignment Operators

Assignment operators that use copy and swap are automatically exception safe and correctly handle self-assignment

#include <string>
#include <iostream>class HasPtr
{
public:friend void swap(HasPtr&, HasPtr&);friend bool operator<(const HasPtr &lhs, const HasPtr &rhs);HasPtr(const std::string &s = std::string()) : ps(new std::string(s)), i(0) { }HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i) { }HasPtr& operator=(HasPtr tmp) {this->swap(tmp);return *this;}~HasPtr() {delete ps;}void swap(HasPtr &rhs) {using std::swap;swap(ps, rhs.ps);swap(i, rhs.i);std::cout << "call swap(HasPtr &rhs)" << std::endl;}void show() const{ std::cout << *ps << std::endl; }
private:std::string *ps;int i;
};void swap(HasPtr& lhs, HasPtr& rhs)
{lhs.swap(rhs);
}bool operator<(const HasPtr &lhs, const HasPtr &rhs)
{return *lhs.ps < *rhs.ps;
}

Essentially, the specific avoiding memory allocation is the reason why it improve performance. As for the pointerlike version, no dynamic memory allocation anyway. Thus, a specific version for it will not improve the performance.

 Move Constructor and Move Assignment
concept:
Like the copy constructor, the move constructor has an initial parameter that is a reference to the class type. Differently from the copy constructor, the reference parameter in the move constructor is an rvalue reference. As in the copy constructor, any additional parameters must all have default arguments
As an example, we’ll define the StrVec move constructor:
StrVec::StrVec(StrVec &&s) noexcept // move won't throw any
exceptions
// member initializers take over the resources in s
: elements(s.elements), first_free(s.first_free),
cap(s.cap)
{
// leave s in a state in which it is safe to run the destructor
s.elements = s.first_free = s.cap = nullptr;
}
After an object is moved from, that object continues to exist. Eventually, the moved-from object will be destroyed, meaning that the destructor will be run on that object. The StrVec destructor calls deallocate on first_free. If we neglected to change s.first_free, then destroying the moved-from object would delete the memory we just moved.

exceptions for move:Because a move operation executes by “stealing” resources, it ordinarily does not itself
allocate any resources. As a result, move operations ordinarily will not throw any
exceptions. When we write a move operation that cannot throw, we should inform the
library of that fact. As we’ll see, unless the library knows that our move constructor
won’t throw, it will do extra work to cater to the possibliity that moving an object of
our class type might throw.
note:the move constructor must ensure that the moved-from object is left in a state such that destroying that object will be harmless

note:Move constructors and move assignment operators that cannot throw exceptions should be marked as noexcept.

    Understanding why noexcept is needed can help deepen our understanding of how
the library interacts with objects of the types we write. We need to indicate that a
move operation doesn’t throw because of two interrelated facts:
First, although move operations usually don’t throw exceptions, they are permitted to do so. 
Second, the library containers provide guarantees as to what they do if an exception happens



move-assignment operator
The move-assignment operator does the same work as the destructor and the move constructor. As with the move constructor, if our move-assignment operator won’t throw any exceptions, we should make it noexcept. Like a copy-assignment operator, a move-assignment operator must guard against self-assignment
StrVec &StrVec::operator=(StrVec &&rhs) noexcept
{
// direct test for self-assignment
if (this != &rhs) {free(); // free existing elementselements = rhs.elements; // take over resources from rhsfirst_free = rhs.first_free;cap = rhs.cap;// leave rhs in a destructible staterhs.elements = rhs.first_free = rhs.cap = nullptr;}return *this;
}



Warning
After a move operation, the “moved-from” object must remain a valid, destructible object but users may make no assumptions about its value
1、setting the pointer members of the moved-from object to nullptr
2、a valid object is one that can safely be given a new value or used in other ways that do not depend on its current value
The Synthesized Move Operations

The compiler synthesizes the move constructor and move assignment only if
a class does not define any of its own copy-control members and only if all
the data members can be moved constructed and move assigned,
respectively.
// the compiler will synthesize the move operations for X and hasX
struct X {int i;         // built-in types can be movedstd::string s; // string defines its own move operations
};
struct hasX {X mem; // X has synthesized move operations
};X x, x2 = std::move(x);        // uses the synthesized move constructorhasX hx, hx2 = std::move(hx); // uses the synthesized move constructor

note:Classes that define a move constructor or move-assignment operator must also define their own copy operations. Otherwise, those members are deleted by default.
Rvalues Are Moved, Lvalues Are Copied ...
If a class has a usable copy constructor and no move constructor, objects will be “moved” by the copy constructor. Similarly for the copy-assignment operator and move-assignment


Copy-and-Swap Assignment Operators and Move


class HasPtr {
public:HasPtr(const std::string &s = std::string()): ps(new std::string(s)), i(0) { }// each HasPtr has its own copy of the string to which ps pointsHasPtr(const HasPtr &p): ps(new std::string(*p.ps)), i(p.i) { }/*HasPtr& operator=(const HasPtr &rhs){auto newp = new string(*rhs.ps); // copy the underlying stringdelete ps;                       // free the old memoryps = newp;                       // copy data from rhs into this objecti = rhs.i;return *this;                    // return this object}*/~HasPtr() { delete ps; }// added move constructorHasPtr(HasPtr&& rhs) noexcept: ps(rhs.ps),i(rhs.i){rhs.ps = 0;}// assignment operator is both the move-and copy-assignment operatorHasPtr& operator=(HasPtr rhs){swap(*this,rhs);return *this;}
private:std::string *ps;int i;
};

For example, assuming both hp and hp2 are HasPtr objects:
hp = hp2; // hp2 is an lvalue; copy constructor used to copy hp2
hp = std::move(hp2); // move constructor moves hp2

    Now let’s look at the assignment operator. That operator has a nonreference parameter, which means the parameter is copy initialized Depending on the type of the argument, copy initialization uses either the copy constructor or the move constructor; lvalues are copied and rvalues are moved. As a result, this single assignment operator acts as both the copy-assignment and move-assignment operator
   In the first assignment, the right-hand operand is an lvalue, so the move constructor is not viable. The copy constructor will be used to initialize rhs. The copy constructor will allocate a new string and copy the string to which hp2 points.
   In the second assignment, we invoke std::move to bind an rvalue reference to hp2. In this case,both the copy constructor and the move constructor are viable.However, because the argument is an rvalue reference, it is an exact match for the move constructor. The move constructor copies the pointer from hp2. It does not allocate any memory.
   Regardless of whether the copy or move constructor was used, the body of the assignment operator swaps the state of the two operands. Swapping a HasPtr exchanges the pointer (and int) members of the two objects. After the swap, rhs will hold a pointer to the string that had been owned by the left-hand side. That string will be destroyed when rhs goes out of scope.
Advice: Updating the Rule of Three
All five copy-control members should be thought of as a unit: Ordinarily, if a class defines any of these operations, it usually should define them all. As we’ve seen, some classes must define the copy constructor, copy-assignment operator, and destructor to work correctly . Such classes typically have a resource that the copy members must copy. Ordinarily, copying a resource entails some amount of overhead. Classes that define the move constructor and move-assignment operator can avoid this overhead in those circumstances where a copy isn’t necessary.




Chapter.13 Copy Constructor相关推荐

  1. C++ explicit constructor/copy constructor note

    C++:explict 作用显示声明构造函数只能被显示调用从而阻止编译器的隐式转换,类似只能用()显示调用,而不能=或者隐式调用 1 #include <iostream> 2 #incl ...

  2. 关于c++中vector的push_back、拷贝构造copy constructor和移动构造move constructor

    问题来自C++ Primer的第十三章练习题的13.48.是这样说的: 定义一个vector<String>并在其上多次调用push_back运行你的程序,并观察String被拷贝了多少次 ...

  3. no copy constructor available or copy constructor is declared #39;explicit#39;

    今天新写了一个类.然后对这个类使用STL中的vector,碰到错误: no copy constructor available or copy constructor is declared 'ex ...

  4. halcon算子盘点:Chapter 13:对象、Chapter 14 区域

    Chapter 13:Object 13.1 Information 1. count_obj  功能:统计一个元组中的对象. 2. get_channel_info  功能:一幅目标图像组成部分的信 ...

  5. 深度探索C++ 对象模型(4)-Default Copy Constructor(2)

    没有Default Constructor, class Myclass{ public://... private:int a;char *str; }; 编译器执行的是"位逐次拷贝(Bi ...

  6. [C++]有关深复制与copy constructor的一些问题与实例

    纸上得来终觉浅,绝知此事要躬行 --- 今天对此话有了实际的领悟.之前学习C++的时候,自以为已经把深复制和复制构造函数等这些知识已经掌握了,但真正写起项目来的时候,还是不能提前考虑这些问题,直到问题 ...

  7. Copy Constructor与赋值运算符

    赋值运算符 '='的默认行为是数据成员的值的相应赋值,默认行为在类的成员中包含指针时容易出现问题,因为它只是赋值了指针的值,但是指针指向的值并未复制.赋值运算符是可以如同其他运算符一样重载的,重载后的 ...

  8. (原創) 哪些地方會用到Copy Constructor和Assignment Operator? (C/C++)

    C#.Java都沒有copy constructor,所以這對大部分programmer都很陌生,簡單地說,凡需要copy的地方,就需要copy constructor: 1.由copy-initia ...

  9. C++ Copy Constructor (拷贝构造函数,复制构造函数)

    1.什么是Copy Constructor? Copy Constructor 是一个特殊的构造函数,一般只有一个参数,这个参数一般是用const修饰的,对自己类的一个引用(reference).什么 ...

  10. 模拟集成电路笔记 | 第一部分 | Chapter 1-3

    模拟集成电路笔记 | 第一部分 | Chapter 1-3 本系列笔记是参考书籍<CMOS模拟集成电路>和中科大相关课程课件而做成,笔记第一版为手写版,现在在手写版的基础上重新编写第二版( ...

最新文章

  1. Java Secret:使用枚举构建状态机
  2. java 调用对象的方法_JAVA调用对象方法的执行过程
  3. 线性最小二乘法的通俗理解
  4. html5输入框增加语音,为任意输入框添加语音输入功能
  5. 手里有200万,如何理财?
  6. ASPNET--Basic Info
  7. 传输表空间--使用Rman方式
  8. C#中提供了三种类型的计时器的比较实验(转自百度文库)
  9. 推荐一款颜值逆天且功能齐全的开源Shell工具
  10. 如何给multisim中导入9012/9013/8050/8550三极管
  11. linux联网是否,Linux命令 查看Linux版本和是否联网
  12. js基础-点击切换div背景颜色
  13. HTML---基础篇
  14. 【Flask】学习笔记 #12 —— JinJa2模板继承与引入
  15. 仿iphone顶部状态栏_无需第三方APP,苹果iPhone手机屏幕录制的方法
  16. Unable to load shared library ‘libgdiplus‘ or one of its dependencies
  17. Halcon入门教程手册
  18. 深入浅出C++ ——初识C++
  19. python3.7批量爬取百度图片/搜狗图片
  20. react根据中文获取拼音_解决 React 中的 input 输入框在中文输入法下的 bug

热门文章

  1. Linux之tar命令
  2. 2000-2021年款雷克萨斯原厂全套维修手册+电路图资料下载
  3. 基于ATmega128单片机的LCD12864显示密码锁
  4. 计算机网络知识点1——概述
  5. 国家统计局指标数据深入分析
  6. [Slackware13.0学习笔记]上网问题
  7. Logit模型和Logistic模型
  8. 如何利用python下载电影_一篇文章教会你利用Python网络爬虫获取电影天堂视频下载链接...
  9. 软考_高级《系统分析师》考试大纲
  10. Zune软件教程 Windows Phone同步攻略