c++11 移动构造_移动赋值_拷贝构造_拷贝赋值调用时机探究
最近对准备深入学习一下c++11所有的新特性,今天研究了一下c++11的std:move和std:forward,在研究这个的时候,需要对c++0xx的拷贝构造,拷贝赋值有一些了解.这个不知道的自己去了解,这里记录一下c++11新加的移动版本
移动构造_移动赋值和拷贝构造_拷贝赋值的比较,文章引用 现代c++之移动构造, 移动赋值, 拷贝构造, 拷贝赋值
的这篇文章来测试.
下面代码在vs2017上面可直接运行
#pragma once
#include <string>
#include <iostream>
#include <memory>
#include <vector>
class CMyString {
private:
char * buf;
int len;
private:
void copy(const char* s) {
buf = new char[len + 1];
memcpy(buf, s, len);
buf[len] = '\0';
}
public:
CMyString() {
std::cout << "构造函数" << ",this:" << this << std::endl;
buf = nullptr;
len = 0;
}
CMyString(const char* str = nullptr) {
if (str == nullptr) {
std::cout << "构造函数" << ",this:" << this << std::endl;
buf = nullptr;
len = 0;
}
else {
std::cout << "构造函数" << str << ",this:" << this << std::endl;
len = strlen(str);
copy(str);
}
}
CMyString(const CMyString& str) {
std::cout << "拷贝构造函数" << str.buf << ",this:" << this << ",right:" << &str << std::endl;
len = str.len;
copy(str.buf);
}
CMyString(CMyString&& str) {
std::cout << "移动构造函数" << str.buf << ",this:" << this << ",right:" << &str << std::endl;
//也可以直接使用std::move
len = str.len;
buf = str.buf;
str.len = 0;
str.buf = nullptr;
}
CMyString& operator=(const CMyString& str) {
std::cout << "拷贝赋值函数" << str.buf << ",this:" << this << ",right:" << &str << std::endl;
if (&str != this) {
if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}
len = str.len;
copy(str.buf);
}
return *this;
}
CMyString& operator=(CMyString&& str) {
std::cout << "移动赋值函数" << str.buf << ",this:" << this << ",right:" << &str << std::endl;
if (this != &str) {
if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}
len = str.len;
buf = str.buf;
str.len = 0;
str.buf = nullptr;
}
return *this;
}
~CMyString() {
if (buf == nullptr)
{
std::cout << "析构函数" << ",this:" << this << std::endl;
}
else
{
std::cout << "析构函数" << buf << ",this:" << this << std::endl;
delete[] buf;
buf = nullptr;
}
}
void print() {
if (buf != nullptr)
std::cout << buf << std::endl;
else
std::cout << "buf is null" << std::endl;
}
};
void func1(CMyString str) {
}
CMyString func2() {
CMyString s("34");//先构造一个CMyString
return s;
/*返回前还会调用拷贝构造函数,或者拷贝赋值,中的一种作为返回值给调用者,或者如果定义了
移动构造函数,移动赋值函数,那就会调用相应的移动版本函数*/
}
void test0() {
CMyString s1("12");
func1(s1); //函数func1值传递,对象str尚未初始化,会调用拷贝构造函数,func1调用结束会调用析构函数
//func1(std::move(s1));
/*函数func1值传递,对象str尚未初始化,会调用移动构造函数,但是后面还要
用到s1,所以不能使用move,func1调用结束会调用析构函数*/
CMyString s2 = func2();
/* 对象s2尚未初始化,会产生临时对象,因func2返回的临时对象属于右值,调用移动构造函数,
如果未定义移动构造函数会调用拷贝构造函数,func2调用结束会调用析构函数*/
CMyString s3 = "56";
s3 = s1; //对象s3已初始化,会调用拷贝赋值函数
//函数调用结束,先析构s3,然后析构s2,再析构s1
}
void test1() {
CMyString s4 = "781";
CMyString s5 = "782";
std::vector<CMyString> v1;
v1.push_back(s4);//调用拷贝构造函数
v1.push_back(std::move(s5)); // 对象尚未初始化,会调用移动构造函数
std::cout << "开始输出v1\n";
for (auto& str : v1)
str.print();
std::vector<CMyString> v2;
v2 = std::move(v1);//调用move后,v1的内存被释放,相当于swap
//v1.swap(v2);
std::cout << "开始输出v1\n";
for (auto& str : v1) //move后,v1中的内存被释放,size为0
str.print();
std::cout << "开始输出v2\n";
for (auto& str : v2)
str.print();
}
void test2() {
CMyString s5 = "9";
s5 = func2(); // 对象s5已初始化, 会产生临时对象,属于右值,调用移动赋值函数
/*
运行结果:
构造函数9,this:009EFB48 ****1
构造函数34,this:009EFA34 ****2
移动构造函数34,this:009EFA78,right:009EFA34 ****3
析构函数,this:009EFA34 ****4
移动赋值函数34,this:009EFB48,right:009EFA78 ****5
析构函数,this:009EFA78 ****6
析构函数34,this:009EFB48 ****7
1:构造s5
2:构造func2中的临时对象s
3:调用移动构造函数构造临时对象
4:析构临时对象s
5:调用移动赋值函数赋值给s5
6:析构临时对象s
7:析构s5
*/
}
//测试结合容器和智能指针使用的情况
void test3()
{
CMyString s1 = "test3_s1";
CMyString s2 = "test3_s2";
//vector < shared_ptr<CMyString>> v1;
//v1.push_back(make_shared<CMyString>(s1));
//v1.push_back(make_shared<CMyString>(move(s2)));
//v1.push_back(make_shared<CMyString>("test3_s3"));
vector < shared_ptr<CMyString>> v2;
v2.push_back(move(make_shared<CMyString>(s1)));
v2.push_back(move(make_shared<CMyString>(move(s2))));
v2.push_back(make_shared<CMyString>("test3_s3"));
}
int test_new()
{
std::cout << "begin test0()" << std::endl;
test0();
std::cout << std::endl;
std::cout << "begin test1()" << std::endl;
test1();
std::cout << std::endl;
std::cout << "begin test2()" << std::endl;
test2();
std::cout << "begin test3()" << std::endl;
test3();
return 0;
}