眺愤 发表于 2025-6-1 00:10:07

C++11特性

Move semantics 移动语义

[!tip]
在 C++98 中,所有的对象拷贝都使用了 拷贝构造函数 或 拷贝赋值运算符,这通常需要深拷贝资源,例如动态分配的内存或文件句柄。这会导致性能开销,尤其是对于临时对象而言(如函数返回值)。
为了解决这个问题,C++11 引入了移动语义,通过区分“拷贝”和“移动”两种语义,大幅提高性能
左值和右值


[*]左值(Lvalue): 指向内存中的某个具体位置,具有持久性

[*]示例:变量名 int a = 10; a 是左值

[*]右值(Rvalue): 临时值,通常是没有持久性的

[*]示例:字面值 10 或临时对象 a + b 的结果

C++11 中,右值被细化为 纯右值(prvalue) 和 亡值(xvalue),其中亡值用于表示即将失去所有权的对象(如返回值)
移动构造函数和移动赋值运算符


[*]移动构造函数:允许从另一个对象中“窃取”资源,而不是复制资源。
[*]移动赋值运算符:将一个对象的资源转移给另一个对象,而不需要深拷贝。
class MyClass {
    int* data;

public:
    // 构造函数
    MyClass(int val) : data(new int(val)) {}

    // 移动构造函数
    MyClass(MyClass&& other) noexcept : data(other.data) {
      other.data = nullptr; // 释放所有权
    }

    // 移动赋值运算符
    MyClass& operator=(MyClass&& other) noexcept {
      if (this != &other) {
            delete data;       // 释放原有资源
            data = other.data; // 转移所有权
            other.data = nullptr;
      }
      return *this;
    }

    ~MyClass() { delete data; }
};标准库函数

C++11
Rvalue references 右值引用

C++11 新增了一种类型引用:右值引用,使用 && 表示,右值引用只绑定到右值。
int x = 0; // `x` is an lvalue of type `int`
int& xl = x; // `xl` is an lvalue of type `int&`
int&& xr = x; // compiler error -- `x` is an lvalue
int&& xr2 = 0; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`

void f(int& x) {}
void f(int&& x) {}

f(x);// calls f(int&)
f(xl); // calls f(int&)
f(3);// calls f(int&&)
f(std::move(x)); // calls f(int&&)

f(xr2);         // calls f(int&)
f(std::move(xr2)); // calls f(int&& x)右值引用的主要目的是:

[*]接收和操作右值(如临时对象)。
[*]实现 移动语义 和 完美转发。
Forwarding references 转发引用

也被称为Universal References(万能引用、通用引用),与std::forward一起使用实现完美转发(Perfect Forwarding。转发引用是通过语法 T&& 创建的,其中 T 是模板类型参数,或使用 auto&&
主要作用是:根据传入参数的值类别(左值或右值)保持其原始类别,从而正确地传递给另一个函数(例如,左值保持为左值,临时对象作为右值转发)
转发引用允许引用根据类型绑定到左值或右值。转发引用遵循引用折叠规则:

[*]T& & 变成 T&
[*]T& && 变成 T&
[*]T&& & 变成 T&
[*]T&& && 变成 T&&
auto 类型推导与左值和右值:
int x = 0; // `x` is an lvalue of type `int`
auto&& al = x; // `al` is an lvalue of type `int&` -- binds to the lvalue, `x`
auto&& ar = 0; // `ar` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`带有左值和右值的模板类型参数推导:
// Since C++14 or later:
void f(auto&& t) {
// ...
}

// Since C++11 or later:
template <typename T>
void f(T&& t) {
// ...
}

int x = 0;
f(0); // T is int, deduces as f(int &&) => f(int&&)
f(x); // T is int&, deduces as f(int& &&) => f(int&)

int& y = x;
f(y); // T is int&, deduces as f(int& &&) => f(int&)

int&& z = 0; // NOTE: `z` is an lvalue with type `int&&`.
f(z); // T is int&, deduces as f(int& &&) => f(int&)
f(std::move(z)); // T is int, deduces as f(int &&) => f(int&&)[!note]
有int x = 10,为什么int&& y = x会出错,而auto&& y = x却没有问题?

[*]int && y = x中,x是一个左值,而y是一个右值引用,右值引用只能绑定右值
[*]auto&& y = x中,auto&&是一个万能引用,x是左值时,其会自动推导为int&,x是右值时,其会自动推到为int&&,所以该式子会自动推导为int& y = x
标准库函数

C++11
用于移动语义的特殊成员函数

复制构造函数和复制赋值运算符在进行复制时被调用,而随着 C++11 引入移动语义,现在有了用于移动的移动构造函数和移动赋值运算符。目的是提高性能,特别是当操作涉及临时对象时
移动构造函数

移动构造函数的作用是“窃取”另一个对象的资源,而不是复制资源,从而避免了不必要的深拷贝操作。
特点:

[*]接受一个右值引用(T&&)作为参数。
[*]通常会转移资源的所有权。
[*]被移动的对象(源对象)会进入“有效但无用”的状态(如将指针置为 nullptr)
#include #include// for std::moveclass MyClass {    int* data;public:    // 构造函数    MyClass(int val) : data(new int(val)) {      std::cout
页: [1]
查看完整版本: C++11特性