move_construction代码
系统默认提供的拷贝构造函数的工作方式是内存拷贝—浅拷贝
浅拷贝: 如果复制的对象中引用以一个外部内容(例如分配在堆上的数据),那么在复制这个对象的时候,让新旧对象指向同一个外部内容,就是浅拷贝。(指针虽然复制了,但所指向的空间内容并没有复制,而是由两个对象共用,两个对象不独立,删除弓箭存在问题)。调用析构函数时会将该指针指向的数据析构两次,造成错误。
深拷贝:如果在复制这个对象的时候为新对象制作了外部对象的独立复制,就是深拷贝。
复制构造函数需为指针变量分配内存空间,并将实参的值拷贝到其中;而赋值操作符它实现的功能仅仅是将‘=’号右边的值拷贝至左值,在左边对象内存不足时,先释放然后再申请。当然赋值操作符必须检测是否是自身赋值,若是则直接返回当前对象的引用而不进行赋值操作
line.h
#ifndef LINE_H
#define LINE_H
#include <string>
#include <iostream>
class Line
{
public:
Line(int lineNo);
~Line(){ std::cerr << " delete a line.";}
void writeChar(std::string chars);
std::string chars(){return m_chars;}
private:
int m_no;
std::string m_chars;
};
#endif // LINE_H
page.h
#ifndef PAGE_H
#define PAGE_H
#include <vector>
#include "line.h"
class Page
{
public:
Page(int no, int lines);
Page(const Page &o);
Page(Page &&o) noexcept;
Page &operator= (const Page &o);
Page &operator=(Page &&o) noexcept;
~Page();
Line *getLine(int lineNo){
return _lines[lineNo - 1];
}
auto lines(){ return _lines; }
private:
int m_no;
std::vector<Line *> _lines;
};
#endif // PAGE_H
line.cpp
#include "line.h"
#include <exception>
using std::domain_error;
using std::string;
Line::Line(int lineNo):m_no{lineNo}{
if(lineNo < 1)
throw domain_error("invalid line number.");
}
void Line::writeChar(string chars){
m_chars = chars;
}
page.cpp
#include "page.h"
#include <iostream>
#include <exception>
using std::domain_error;
using std::cerr;
Page::Page(int no, int lines):m_no{no}
{
if(no < 1)
throw domain_error("invalid line number.");
for(int i = 1; i < lines + 1; i++)
_lines.push_back(new Line(i));
cerr << " call Page's parameter constructor.";
cerr << " The "<< m_no
<<" Page has " << _lines.size() << " lines now.\n";
}
Page::Page(const Page &o):
m_no{o.m_no}
{
for(auto l:o._lines)
_lines.push_back(new Line{*l});
cerr << " call Page's copy constructor.";
cerr << " This Page has " << _lines.size() << " lines now.\n";
}
Page::Page(Page &&o)noexcept:
m_no{o.m_no},_lines{o._lines} //普通成员复制,资源成员浅复制
{
o._lines.clear(); //资源成员完成资源移动
cerr << " call Page's move constructor.";
cerr << " The "<< m_no
<<" Page has " << _lines.size() << " lines now.\n";
}
//深赋值
Page &Page::operator=(const Page &o)
{
cerr << " call Page's operator=(Page &).";
m_no=o.m_no; //普通成员赋值
// cerr << " _lines=" <<_lines.size() << " before erase,";
for(auto l:_lines) //资源成员深赋值-擦除左值资源
delete l;
_lines.clear();
// cerr << " o._lines=" <<o._lines.size() << " before copy,";
for(auto l:o._lines) //资源成员深赋值-复制
_lines.push_back(new Line{*l});
// cerr << " o._lines=" << o._lines.size() << " after copy,";
// cerr << " _lines="<< _lines.size() << " now.\n";
return *this;
}
//移动赋值
Page &Page::operator=(Page &&o) noexcept
{
for(auto l:_lines) //清理左值对象的资源
delete l;
m_no=o.m_no; //普通成员赋值
_lines = o._lines; //资源成员浅赋值
o._lines.clear(); //资源成员完成资源移动
return *this; //返回赋值表达式的值
}
Page::~Page()
{
cerr << " call Page's destructor.";
for(auto &l:_lines){
delete l;
l = nullptr;
}
cerr << " This Page had " << _lines.size() << " lines before.\n";
}
main.cpp
#include <iostream>
#include "page.h"
#include "line.h"
using namespace std;
Page p0(5,10);
Page f()
{
Page p(3, 2);
cerr << " in the f().\n";
p.getLine(1)->writeChar("hello");
return p;
}
Page g()
{
cerr << " in the g().\n";
return Page(4, 2);
}
int main()
{
cerr << "\n1 Page p1 = Page(1,2);" << endl;
Page p1 = Page(1,2); //默认省略移动操作,直接触发参数构造函数
cerr << "\n2 Page p2 {Page(2,3)};" << endl;
Page p2 {Page(2,3)};//默认省略移动操作,直接触发参数构造函数
cerr << "\n3 Page p3 = p1;" << endl;
Page p3 = p1; //触发复制构造函数
cerr << "\n4 Page p4 {p1};" << endl;
Page p4 {p2}; //触发复制构造函数
cerr << "\n5 Page p5 = std::move(p3);" << endl;
Page p5 = std::move(p3); //显式触发移动构造函数
cerr << "Page p3 has " <<
p3.lines().size() << " lines now." << endl;
cerr << "\n6 Page p6 {std::move(p4)};" << endl;
Page p6 {std::move(p4)}; //显式触发移动构造函数
cerr << " Page p4 has " << p4.lines().size() << " lines now."<<endl;
cerr << "\n7 Page p7 = std::move(Page(2,2));" << endl;
Page p7 = std::move(Page(2,2));//显式触发移动构造函数
cerr << "\n8 Page p8 {std::move(Page(3,2))};" << endl;
Page p8 {std::move(Page(3,2))};//显式触发移动构造函数
cerr << "\n9 Page p9 {f()};" << endl;
Page p9 {f()};//默认省略移动操作,但可能被优化掉
cerr << "\n10 Page p10 {g()};" << endl;
Page p10 {g()};//默认省略移动操作,但可能被优化掉
cerr << "\n11 Page &&p11 {f()};" << endl;
Page &&p11 {f()};//默认省略移动操作,但可能被优化掉
cerr << "\n12 p1 = p2" << endl;
p1 = p2;//触发operator=(Page &)复制赋值操作
cerr << "\n13 p1 = Page(2,2);" << endl;
p1 = Page(2,2);//触发operator=(Page &&)移动赋值操作
cerr << "\n\n------brefore return 0;---------\n";
return 0;
}