C++ 的右值引用和移动语义

在 C++ 11 之前,常量引用可以避免拷贝,直接传递临时对象。

ini 复制代码
int x = 10;
const int &ref = x + 1; // 合法,绑定到临时对象
// int &ref2 = x + 1; // 错误,非 const 引用不能绑定临时对象

函数参数中的常量引用:

c 复制代码
#include <iostream>
using namespace std;
​
void print(const int &value) { // 常量引用,避免拷贝且防止修改
    cout << value << endl;
}
​
int main() {
    int x = 10;
    print(x);      // 传递变量
    print(20);     // 传递临时对象
    print(x + 30); // 传递表达式
    return 0;
}

C++ 11 引入了右值引用(&&),用于支持移动语义和完美转发,优化性能。

左值(Lvalue)是指有固定内存地址,可以取地址的对象(比如变量)。右值(Rvalue)是指临时对象或字面量,没有固定地址(比如x + 1、字面量42)。

右值引用可以绑定到右值,用于实现移动语义(避免拷贝):

c 复制代码
#include <iostream>
using namespace std;
​
void print(int &lvalue) {
    cout << "左值: " << lvalue << endl;
}
​
void print(int &&rvalue) {
    cout << "右值: " << rvalue << endl;
}
​
int main() {
    int x = 10;
    print(x);      // 调用左值版本
    print(20);     // 调用右值版本
    print(x + 30); // 调用右值版本
    return 0;
}

输出:

makefile 复制代码
左值: 10
右值: 20
右值: 40

右值引用常用于移动构造和移动赋值,避免深拷贝:

arduino 复制代码
#include <iostream>
#include <string>
using namespace std;
​
class MyString {
private:
    char *data;
public:
    MyString(const char *str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
        cout << "构造: " << data << endl;
    }
​
    // 移动构造函数
    MyString(MyString &&other) noexcept : data(other.data) {
        other.data = nullptr; // 转移资源
        cout << "移动构造" << endl;
    }
​
    ~MyString() {
        if (data) {
            cout << "析构: " << data << endl;
            delete[] data;
        }
    }
};
​
int main() {
    MyString s1("Hello");
    MyString s2 = move(s1); // move 函数将 s1 转换为右值,触发移动构造,避免拷贝。
    return 0;
}

输出:

makefile 复制代码
构造: Hello
移动构造
析构: Hello

在这段代码中:

kotlin 复制代码
// 移动构造函数
MyString(MyString &&other) noexcept : data(other.data) {
    other.data = nullptr; // 转移资源
    cout << "移动构造" << endl;
}

MyString &&other 表示右值引用,表示 other 是一个右值(临时对象或即将销毁的对象)。: data(other.data) 表示将 other 的 data 指针直接赋值给当前对象的 data。other.data = nullptr,将 other 的 data 置为空,避免 other 析构时释放同一块内存。noexcept 表示这个函数不会抛出异常,移动构造函数通常需要时 noexcept 的,标准库(如 std::vector )在移动元素时会优先选择 noexcept 的移动构造函数,否则可能退回到拷贝。

如果没有移动构造函数,MyString s2 = s1 会调用拷贝构造函数,默认会执行深拷贝。如果没有定义拷贝构造函数,编译器会生成默认的拷贝构造函数,导致浅拷贝(s1 和 s2 共享 data),析构时会重复释放内存,引发崩溃。

实现拷贝构造函数:

arduino 复制代码
#include <iostream>
#include <cstring>
using namespace std;
​
class MyString {
private:
    char *data;
public:
    // 构造函数
    MyString(const char *str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
        cout << "构造: " << data << endl;
    }
​
    // 拷贝构造函数
    MyString(const MyString &other) {
        data = new char[strlen(other.data) + 1];
        strcpy(data, other.data);
        cout << "拷贝构造: " << data << endl;
    }
​
    // 移动构造函数
    MyString(MyString &&other) noexcept : data(other.data) {
        other.data = nullptr;
        cout << "移动构造" << endl;
    }
​
    // 析构函数
    ~MyString() {
        if (data) {
            cout << "析构: " << data << endl;
            delete[] data;
        }
    }
};
​
int main() {
    MyString s1("Hello");
    MyString s2 = move(s1); // 移动构造
    return 0;
}

如果 s1 即将销毁(比如临时对象),这种拷贝是浪费的。移动构造函数通过将 s1 的 data 直接给 s2,避免了深拷贝。s1 的 data 被置为 nullptr,确保它不会重复释放内存。移动操作(指针赋值)比拷贝(内存分配和复制)快得多。

std::move 的作用并不是真正"移动"数据,它只是将对象转换为右值,告诉编译器可以调用移动构造函数。

移动语义将资源从一个对象"转移"到另一个对象,而不是拷贝。它主要用于临时对象(右值)即将销毁或者需要高校转移资源(如动态内存、文件句柄)。

相关推荐
June`1 小时前
warp shuffle指令
c++·人工智能·算法·cuda
乱七八糟的屋子1 小时前
【C++数值计算】NumCpp超详细入门教程(纯正Numpy语法、零学习成本、C++首选科学计算库、性能压测对比)
c++·数值计算·numpy·高性能计算·科学计算·ndarray
choumin1 小时前
C程序能调用extern “C“声明的带默认参数的C++函数吗?
c语言·c++·extern c·默认参数
AmyLin_20012 小时前
PDF 色彩保真工程实践【3】上手实践:工程结构、依赖集成与一键构建运行
c++·visualstudio·pdf·zlib·vcpkg·libtiff·cmyk
并不喜欢吃鱼2 小时前
从零开始 C++------ 十六.深度拆解 C++ 智能指针:unique_ptr/shared_ptr/weak_ptr 底层模拟、内存泄漏根治
开发语言·c++
不相心 -w-2 小时前
Cmake的基础用法
linux·开发语言·c++
撑伞的鱼99372 小时前
C++开发用什么AI编程工具效果好?2026年实测横评(附选型指南)
开发语言·c++·ai编程·cursor
j7~3 小时前
【Linux】二十八.线程篇五《Linux多线程编程:线程同步之条件变量》---详解
linux·运维·c++·学习·条件变量·线程同步
王老师青少年编程3 小时前
2026年全国青少年信息素养大赛算法应用主题赛C++赛项【决赛】模拟卷3:文末附答案
c++·答案·模拟题·2026年·青少年信息素养大赛·算法应用主题赛·决赛
程序喵大人3 小时前
【C++进阶】STL容器与迭代器 - 10 把容器、迭代器和数据流串成一个小程序
开发语言·c++·容器·小程序·迭代器·stl