主页 > 互联网  > 

C++移动语义

C++移动语义
移动语义

C++11中提供了一个新特性-移动语义,使用std::move实现,用法为

std::move MyClass A; MyClass B = std::move(A);

移动语义的意义是当一个临时变量生命周期要结束了,但是需要使用其初始化另外一个变量,例如函数的返回值(非指针),就是一个临时变量。我们知道,使用一个类去初始化另外一个类可以使用拷贝的方式,即调用类的拷贝构造函数或赋值运算符函数,为了防止类中内容出现指针悬垂情况,类的拷贝构造和赋值运算符都会写成深拷贝的模式,即需要重新申请一块内存再将数据存放进去。而移动语义则是直接占为己有,即把数据直接转移到另一个实例化的类中,避免了拷贝带来的性能花销。std::move函数的用处就是告诉编译器,这个对象已经不需要了,可以直接转给别的类使用。 下面展示一个例子:

#include <iostream> #include <vector> using namespace std; class MyClass { public: MyClass(const char* _name) { id = 0; name = new char[256]; memset(name, 0, 256); strcpy_s(this->name, 256, _name); cout << "Call Constructor, name address = " << static_cast<void*>(name) << endl; } MyClass(const MyClass& other) { if (this->name) delete this->name; this->name = new char[256]; memset(this->name, 0, 256); strcpy_s(this->name, 256, other.name); this->id = other.id; cout << "Call Copy Constructor, name address = " << static_cast<void*>(name) << endl; } ~MyClass() { cout << "Call Destructor, name address = " << static_cast<void*>(name) << endl; if (name) delete[] name; } private: int id; char* name = nullptr; }; MyClass func() { return MyClass("aaa"); } int main() { MyClass a = move(func()); MyClass b = func(); }

运行这段代码会发现拷贝构造函数被调用了,原因是因为类中没有定义移动构造函数,编译器只能去调用拷贝构造函数。

移动构造函数

下面就来实现移动拷贝构造函数。为了实现移动语义,C++11新增了一个新特性,叫做右值引用,使用双&定义。单一&定义的是左值引用。

int a = 0; int& b = a; // 左值引用 int&& c; // 右值引用

让编译器将一个变量匹配成右值引用的情况有两个

一个在执行语句后就会被释放的临时变量使用std::move标记的变量

将变量匹配成右值引用是实现移动语义的基础

实现移动构造函数的思路就是移动语义的含义,直接将另一个类的数据内存直接接管,同时还需要注意一个重点,就是把传入对象的数据清除。 移动构造函数的参数就是上述说的右值引用,在上述类中添加上移动构造函数:

// 实现深拷贝类 class MyClass { public: MyClass(const char* _name) { id = 0; name = new char[256]; memset(name, 0, 256); strcpy_s(this->name, 256, _name); cout << "Call Constructor, name address = " << static_cast<void*>(name) << endl; } MyClass(const MyClass& other) { if (this->name) delete this->name; this->name = new char[256]; memset(this->name, 0, 256); strcpy_s(this->name, 256, other.name); this->id = other.id; cout << "Call Copy Constructor, name address = " << static_cast<void*>(name) << endl; } // 移动构造函数 MyClass(MyClass&& other) noexcept { this->id = move(other.id); // 直接移动 this->name = other.name; // move对原始指针没用,直接接管即可 other.name = nullptr; cout << "Call Move Constructor, name address = " << static_cast<void*>(name) << endl; } MyClass& operator=(const MyClass& other) { if (this != &other) { if (this->name) delete this ->name; this->name = new char[256]; memset(this->name, 0, 256); strcpy_s(this->name, 256, other.name); this->id = other.id; } cout << "Call operator, name address = " << static_cast<void*>(name) << endl; return *this; } ~MyClass() { cout << "Call Destructor, name address = " << static_cast<void*>(name) << endl; if (name) delete[] name; } private: int id; char* name = nullptr; }; 总结

当出现一些只为了提供给另外一个类实例化的变量时,例如函数返回临时变量或是将一个实例化的类push_back到vector中而无其他用处,就可以使用移动语义的方式,以减少程序运行时出现的拷贝,减少性能消耗。

标签:

C++移动语义由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C++移动语义