C++11特性

守听  论坛元老 | 2025-4-18 10:16:33 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 2147|帖子 2147|积分 6441

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
Move semantics 移动语义

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


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

    • 示例:变量名 int a = 10; a 是左值

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

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

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


  • 移动构造函数:允许从另一个对象中“窃取”资源,而不是复制资源。
  • 移动赋值运算符:将一个对象的资源转移给另一个对象,而不需要深拷贝。
  1. class MyClass {
  2.     int* data;
  3. public:
  4.     // 构造函数
  5.     MyClass(int val) : data(new int(val)) {}
  6.     // 移动构造函数
  7.     MyClass(MyClass&& other) noexcept : data(other.data) {
  8.         other.data = nullptr; // 释放所有权
  9.     }
  10.     // 移动赋值运算符
  11.     MyClass& operator=(MyClass&& other) noexcept {
  12.         if (this != &other) {
  13.             delete data;       // 释放原有资源
  14.             data = other.data; // 转移所有权
  15.             other.data = nullptr;
  16.         }
  17.         return *this;
  18.     }
  19.     ~MyClass() { delete data; }
  20. };
复制代码
标准库函数

C++11
Rvalue references 右值引用

C++11 新增了一种范例引用:右值引用,使用 && 表示,右值引用只绑定到右值。
  1. int x = 0; // `x` is an lvalue of type `int`
  2. int& xl = x; // `xl` is an lvalue of type `int&`
  3. int&& xr = x; // compiler error -- `x` is an lvalue
  4. int&& xr2 = 0; // `xr2` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`
  5. void f(int& x) {}
  6. void f(int&& x) {}
  7. f(x);  // calls f(int&)
  8. f(xl); // calls f(int&)
  9. f(3);  // calls f(int&&)
  10. f(std::move(x)); // calls f(int&&)
  11. f(xr2);           // calls f(int&)
  12. 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 范例推导与左值和右值:
  1. int x = 0; // `x` is an lvalue of type `int`
  2. auto&& al = x; // `al` is an lvalue of type `int&` -- binds to the lvalue, `x`
  3. auto&& ar = 0; // `ar` is an lvalue of type `int&&` -- binds to the rvalue temporary, `0`
复制代码
带有左值和右值的模板范例参数推导:
  1. // Since C++14 or later:
  2. void f(auto&& t) {
  3.   // ...
  4. }
  5. // Since C++11 or later:
  6. template <typename T>
  7. void f(T&& t) {
  8.   // ...
  9. }
  10. int x = 0;
  11. f(0); // T is int, deduces as f(int &&) => f(int&&)
  12. f(x); // T is int&, deduces as f(int& &&) => f(int&)
  13. int& y = x;
  14. f(y); // T is int&, deduces as f(int& &&) => f(int&)
  15. int&& z = 0; // NOTE: `z` is an lvalue with type `int&&`.
  16. f(z); // T is int&, deduces as f(int& &&) => f(int&)
  17. 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)
[code]#include #include  // for std::moveclass MyClass {    int* data;public:    // 构造函数    MyClass(int val) : data(new int(val)) {        std::cout
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

守听

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表