C++11 移动构造函数

一、引言

移动构造函数是什么?先举个例子,你有一本书,你不想看,但我很想看,那么我有哪些方法可以让我能看这本书?有两种做法,一种是你直接把书交给我,另一种是我去买一些稿纸来,然后照着你这本书一字一句抄到稿纸上。

显然,第二种方法很浪费时间,但这正是有些深拷贝构造函数的做法,而移动构造函数便能像第一种做法一样省时,第一种做法在 C++ 中叫做完美转发。


二、左值和右值

何为左值?能用取址符号 & 取出地址的皆为左值,剩下的都是右值。

而且,匿名变量一律属于右值。

int i = 1; // i 是左值,1 是右值

int GetZero {
   
   
    int zero = 0return zero;
}
//j 是左值,GetZero() 是右值,因为返回值存在于寄存器中
int j = GetZero();

//s 是左值,string("no name") 是匿名变量,是右值
string s = string("no name");

三、深拷贝构造函数

用 g++ 编译器编译下列代码时记得加上参数 -fno-elide-constructors

#include <iostream>
#include <string>

using namespace std;

class Integer {
   
   
public:
    //参数为常量左值引用的深拷贝构造函数,不改变 source.ptr_ 的值
    Integer(const Integer& source)
      : ptr_(new int(
### C++ 移动构造函数的使用与实现 C++11 引入了移动语义(Move Semantics),其中移动构造函数是一个重要的组成部分。它允许资源(如动态分配的内存、文件句柄等)在对象之间高效地转移,而无需进行深拷贝操作。以下是关于移动构造函数的详细说明: #### 1. 移动构造函数的基本概念 移动构造函数是一种特殊的构造函数,用于从右值(rvalue)初始化一个对象。右值通常是临时对象或即将销毁的对象,因此可以直接“移动”其资源,而无需复制[^1]。 例如,在 `std::vector` 扩展自身存储空间时,如果没有移动构造函数,会频繁触发拷贝构造函数,导致不必要的性能开销。有了移动构造函数后,它可以将资源直接“移动”到新位置,避免深拷贝[^1]。 #### 2. 移动构造函数的声明与定义 移动构造函数通常通过接受右值引用(`T&&`)作为参数来声明。以下是一个简单的示例: ```cpp class MyClass { public: // 普通构造函数 MyClass(int value) : data(new int(value)) { std::cout << "Constructor called" << std::endl; } // 拷贝构造函数 MyClass(const MyClass& other) : data(new int(*other.data)) { std::cout << "Copy Constructor called" << std::endl; } // 移动构造函数 MyClass(MyClass&& other) noexcept : data(other.data) { std::cout << "Move Constructor called" << std::endl; other.data = nullptr; // 确保原对象不再拥有资源 } ~MyClass() { delete data; std::cout << "Destructor called" << std::endl; } private: int* data; }; ``` #### 3. 移动构造函数的调用场景 移动构造函数会在以下情况下被调用: - 当返回局部对象时,编译器可能会优化为直接调用移动构造函数。 - 当将临时对象传递给需要右值引用的函数参数时。 - 当显式使用 `std::move` 将左值转换为右值时。 例如: ```cpp MyClass createObject() { return MyClass(42); // 返回临时对象,可能触发移动构造函数 } int main() { MyClass obj1 = createObject(); // 调用移动构造函数 MyClass obj2 = std::move(obj1); // 显式调用移动构造函数 return 0; } ``` #### 4. 编译器生成的移动构造函数 如果类中没有显式定义移动构造函数,并且满足一定条件(如类成员支持移动语义),编译器会自动生成默认的移动构造函数[^2]。然而,某些情况下编译器会抑制合成移动构造函数的生成,例如: - 类中定义了删除的移动构造函数。 - 类中显式定义了拷贝构造函数或拷贝赋值运算符。 #### 5. 移动构造函数与性能优化 移动构造函数的主要目的是减少资源复制的开销。例如,对于包含动态分配内存的类,移动构造函数可以通过简单地转移指针来完成初始化,而不是复制整个数据结构[^3]。 以下是一个对比示例: ```cpp // 拷贝构造函数 MyClass(const MyClass& other) : data(new int(*other.data)) {} // 移动构造函数 MyClass(MyClass&& other) noexcept : data(other.data) { other.data = nullptr; } ``` 在上述代码中,移动构造函数直接接管了 `other.data` 的所有权,而拷贝构造函数则需要分配新的内存并复制数据。 #### 6. 注意事项 - 移动构造函数应标记为 `noexcept`,以确保标准库容器(如 `std::vector`)能够安全地使用它。 - 在移动构造函数中,必须确保源对象的状态是有效的,即使它不再拥有资源。 --- ### 示例代码 以下是一个完整的代码示例,展示移动构造函数的使用: ```cpp #include <iostream> #include <utility> // std::move class Resource { public: Resource(int size) : data(new int[size]), size(size) { std::cout << "Constructor: Allocated " << size << " integers" << std::endl; } Resource(const Resource& other) : data(new int[other.size]), size(other.size) { std::copy(other.data, other.data + size, data); std::cout << "Copy Constructor: Copied " << size << " integers" << std::endl; } Resource(Resource&& other) noexcept : data(other.data), size(other.size) { other.data = nullptr; other.size = 0; std::cout << "Move Constructor: Moved resource" << std::endl; } ~Resource() { delete[] data; std::cout << "Destructor: Freed resource" << std::endl; } private: int* data; int size; }; Resource createResource() { return Resource(100); // 返回临时对象 } int main() { Resource r = createResource(); // 调用移动构造函数 return 0; } ``` ---
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值