移动语义和右值引用

移动语义和右值引用

移动语义和右值引用

案例:

1
2
3
4
5
6
7
8
9
vector<string> allcps(const vector<string>& vs)
{
vector<string> temp;
...//存储vs中的所有的值
return temp;
}
vector<string> vstr;
vector<string> vstr_copy1(vstr);//#1
vector<string> vstr_copy2(allcps(vstr));//#2

vstr_copy2会先调用allcps函数,首先产生一个temp变量(allcps内部),然后生成一个临时返回对象并删除temp变量,再调用拷贝构造,最后再删除临时返回对象。

如果不删除原来的字符,仅仅是修改一下指向,这种方法叫做移动语义

要实现移动语义,就要让编译器知道何时需要复制何时不需要,所以就要使用右值引用

移动构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class Test
{
private:
char* pc;
public:
Test();
Test(const Test & t);
Test(Test && t);//移动构造函数。因为要更改t,所以不能加上const
~Test();
Test operator+(const Test& t)const;
}

Test::Test()
{
pc = new char[100];
for(int i =0;i<100;++i){pc[i]=i;}
}
Test::Test(const Test& t)
{
pc = new char[100];
for(int i=0;i<100;++i){pc[i]=t.pc[i];}
}
Test::Test(Test&& t)
{
pc=t.pc;
t.pc=nullptr;//pc和t.pc指向同一块内存,调用析构时可能会出现问题,不能对同一块地址delete两次
//所以将t.pc设置为空地址,因为delete空指针是可以的
}
Test::~Test()
{
delete [] pc;
}
Test Test::operator+(const Test& t) const
{
Test temp ;
for (int i = 0; i < 100; ++i)
{
temp.pc[i] = this->pc[i]+t.pc[i];
}
return temp;
}

int main()
{
Test one;
Test two = one;//调用普通的拷贝构造。因为one是左值
Test three;
Test four(one+three);//调用移动构造函数。因为one+three为右值
}
//在c++98没有引入右值引用时,如果实参为右值,const引用形参将执行一个临时变量

赋值

适用于构造函数的移动语义也适用于赋值运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Test& Test::operator=(const Test& t) 
{
if(this == &t)
return *this;
delete [] pc;
pc = new char[100];
for(int i=0;i<100;i++)
{
pc[i]=t.pc[i];
}
return *this;
}

Test& Test::operator=(Test&& t) //同样没有const修饰参数,因为要改动
{
if(this == &t)
return *this;
delete [] pc;
pc = t.pc;
t.pc = nullptr;

return *this;
}

强制移动

移动构造函数和移动赋值运算符号都是使用右值,如果只有左值怎么办?

  1. 可以使用static_cast<>将对象的类型强行转为Test &&

  2. 使用utility头文件中的std::move()

     `Test four = std::move(one)`
    

std::move并非一定会使用移动操作,例如:

1
2
3
4
5
Chunk one;
...
Chunk two;
two = std::move(one);//如果定义了移动赋值运算符,这样没有问题
//如果没有定义移动赋值运算符,将使用复制赋值运算符,如果也没有定义,那将不允许
作者

步步为营

发布于

2024-05-08

更新于

2025-03-15

许可协议