13.6 对象移动
这一节本质上是对性能进行优化,(对设计资源管理的类的性能优化),就算不知道这一节的的内容,一样的可以编码,但是如果设计的类对性能要求较高,就需要这一节的内容了。
在使用vector装自定义的类型的类型时,如果容量不足会开辟空间,将原来的元素拷贝到新的空间的,原来的元素会被销毁,我们知道原来的元素拷贝到新空间之后,不会再使用,如果对象非常的大,那么拷贝是会消耗比较大的性能的,既然原来的对象拷贝之后就不再使用,那么有没有什么方法,能够让原本对象的内容直接拷贝到新的内存空间中呢,C++提供了移动操作,用来将原来对象“移动”到新的内存空间中。使用移动的方式可以避免拷贝。
目前看来,“移动”操作和swap()类型可以大幅度提升性能的前提是类中有标准库容器,或者有指针指向的动态分配的对象。
13.6.1 右值引用
因为要支持移动操作,C++定义了右值引用。
使用&&来获取右值引用,有了右值引用,我们就可以其绑定的资源“移动”到另一个对象中。
右值引用用来绑定字面值常量,返回右值的表达式以及要求转换类型的表达式 , (要求转换类型的意思应该是表达式中既有左值也有右值) ,
左值具有持久的状态,直到离开作用域才被销毁,而右值是字面值常量要么是表达式中的临时对象,所引用的对象即将被销毁且没有其他的用户。
所有的变量都是左值,因为右值引用的变量也是左值,而左值不能直接使用右值绑定。
需要使用std::move(obj)将左值转化为右值类型,但是这样意味着obj的资源将被右值引用的变量所接管,后续除了对obj进行赋值和销毁,我们不要再使用它。
练习
13.45
一句话:
左值引用可以绑定左值,const 左值引用和右值引用可以绑定右值。
左值引用可以绑定返回值类型为引用的函数、赋值、下标、解引用、前置递减递增运算符等返回左值的表达式的结果上。
const类型的左值引用和右值引用可以绑定在返回非引用类型的函数、算术、关系、位、后置递增递减等返回右值的表达式的结果上。
13.46
int &&r1 = f();
int &r2 = vi[0];
int & r3 = r1;
int &&r4 = vi[0] * f();
13.47
这里完善了之前的MyString类,添加了拷贝构造函数、拷贝内赋值运算符、free()等函数
.h文件
#pragma once
#include <memory>
class MyString {
friend void print(std::ostream& s, const MyString& str);
public:
MyString();
MyString(const char*);
MyString(const MyString&);
MyString& operator=(const MyString&);
~MyString();
size_t size()const;
private:
size_t get_char_arr_len(const char *);
void free();
static std::allocator<char> alloc;
char* begin;
char* end;
char* last;
};
.cpp文件
#include "pch.h"
#include "MyString.h"
#include <algorithm>
#include <iostream>
using std::cout;
using std::endl;
std::allocator<char> MyString::alloc;
MyString::MyString()
{
begin = alloc.allocate(1);
alloc.construct(begin, '\0');
end = begin;
last = end + 1;
}
MyString::MyString(const char * c)
{
size_t len = get_char_arr_len(c) + 1;
begin = alloc.allocate(len);
end = begin + len - 1;
last = end + 1;
size_t index = 0;
for (auto iter = begin; iter != end; ++iter)
{
alloc.construct(iter, c[index]);
++index;
}
*end = '\0';
}
MyString::MyString(const MyString & s)
{
cout << "调用了拷贝构造函数" << endl;
auto temp_begin = alloc.allocate(s.size() + 1);
auto temp_iter = temp_begin;
for (auto iter = s.begin; iter != s.end; ++iter)
{
alloc.construct(temp_iter