【c++11】C++11为什么需要std::ref/reference_wrapper

C++11引入的std::ref和reference_wrapper主要用于解决引用传递的问题,特别是在容器、lambda表达式和线程中。它们避免了对象不必要的拷贝,提高效率。std::ref用于将引用包装成可存储的类型,而reference_wrapper则提供了一种在泛型代码中存储和传递引用的方式。在std::promise示例中,std::ref用于将future对象作为引用传递给任务函数。此外,reference_wrapper还可以用于创建引用数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 看到一个用法
  • 容器里是 std::reference_wrapper 对象
    std::vector<std::reference_wrapper<ParticipantObserver>> observers_;

  • 总结了下,可能以下三种情况需要用到:
  • vector里不能直接存储引用,又不想做拷贝
  • 丢入lamba或者函数是引用,
  • 如果设计意图就是执行完毕后被对象会被修改

C++11为什么需要std::ref/reference_wrapper?

<
<think>嗯,用户问的是std::reference_wrapper的作用和原理,我需要先回忆一下这个知识点的内容。首先,std::reference_wrapperC++中是用来包装引用的,对吧?那普通的引用和它有什么不同呢?我记得普通的引用在容器里比如vector不能直接存储,比如vector<int&>是不允许的,这时候就需要用到reference_wrapper。 那用户可能是在处理需要容器保存引用的情况,或者需要在泛型编程中传递引用的时候。比如,使用算法时想要避免拷贝对象,而用引用来提高效率。这时候reference_wrapper就可以派上用场了。 接下来要解释它的原理。reference_wrapper内部应该有一个指针,因为引用本质上就是指针的语法糖,而reference_wrapper通过指针来模拟引用的行为。然后它重载了operator(),允许隐式转换回原始类型的引用,这样在使用的时候可以像直接使用引用一样方便。 可能用户还不太清楚为什么需要这个东西,直接使用指针不行吗?这里需要说明reference_wrapper提供了类似引用的语义,比如不能为空,并且在某些模板元编程中更容易处理,因为它可以保持值类型的一致性,而指针可能需要额外的处理。 另外,reference_wrapper支持拷贝和赋值,而普通的引用不行,这也是它能在容器中使用的原因。比如,当把多个reference_wrapper对象放进vector时,它们的赋值操作是允许的,而引用则不行,因为引用一旦初始化后不能改变指向的对象。 可能还需要提到std::refstd::cref这些辅助函数,用来方便地创建reference_wrapper对象,这样用户就不需要显式地构造它,而是通过函数模板自动推导类型。 用户可能还关心使用场景,比如在绑定参数到函数对象时,或者在多线程中传递参数给线程函数时,保持引用而不是拷贝。或者在使用某些标准库算法如std::sort时,想要比较对象通过引用访问而不是复制,这时候可以用reference_wrapper来包裹元素,避免拷贝开销。 需要注意的是,reference_wrapper和普通引用的区别,比如它必须显式转换回引用,或者在某些情况下自动转换。比如在调用一个期望接受引用的函数时,reference_wrapper会自动转换,所以用户可能不需要做额外的工作。 最后,总结一下它的主要用途:允许在不能直接使用引用的地方(如容器)存储引用,提供引用的语义,同时具备可拷贝和可赋值的特性,通过内部指针实现,并支持隐式转换回原始引用类型。</think>`std::reference_wrapper` 是 C++ 标准库中的一个工具类,主要用于在需要“引用语义”但无法直接使用原生引用的场景中(例如容器存储、模板参数传递等)包装对象引用。它的核心作用是让引用具备可拷贝、可赋值和可存储的特性,同时保留引用的行为。 -- ### **作用** 1. **容器存储引用** 原生引用(如 `int&`)无法直接存入容器(如 `std::vector`),因为容器要求元素类型可拷贝且可赋值,而引用本身不满足这些要求。`std::reference_wrapper<T>` 通过包装引用,允许将引用存入容器: ```cpp std::vector<std::reference_wrapper<int>> vec; int a = 10, b = 20; vec.push_back(a); // 存入引用 vec.push_back(b); ``` 2. **按引用传递到泛型代码** 在模板编程中,若需要将参数按引用传递给函数对象(如 `std::bind` 或算法),原生引用可能因类型推导丢失引用语义。`std::reference_wrapper` 可以显式保留引用: ```cpp void foo(int& x); int a = 10; auto bound_foo = std::bind(foo, std::ref(a)); // 按引用绑定参数 ``` 3. **模拟引用的可赋值性** 原生引用一旦初始化后不能改变指向的对象,而 `std::reference_wrapper` 可以通过赋值操作切换引用的目标: ```cpp int a = 10, b = 20; std::reference_wrapper<int> ref = a; ref = b; // 现在 ref 指向 b ``` --- ### **原理** 1. **内部实现** `std::reference_wrapper<T>` 内部通常通过存储一个指向 `T` 的指针(`T*`)来模拟引用。其大致简化实现如下: ```cpp template <typename T> class reference_wrapper { private: T* ptr; // 指向目标对象的指针 public: explicit reference_wrapper(T& obj) : ptr(&obj) {} operator T&() const { return *ptr; } // 隐式转换为原生引用 T& get() const { return *ptr; } // 显式获取引用 }; ``` 2. **隐式转换为原生引用** 通过重载 `operator T&()`,`std::reference_wrapper` 可以隐式转换为 `T&`,从而在使用时与原生引用行为一致: ```cpp void bar(int& x); int a = 10; std::reference_wrapper<int> ref = a; bar(ref); // 隐式转换为 int&,直接传递引用 ``` 3. **支持标准库工具** `std::reference_wrapper` 支持 `std::invoke`、`std::function` 等工具,因为它能隐式提供引用的调用语义。 --- ### **辅助函数** 标准库提供了两个辅助函数简化创建: - `std::ref(obj)`:生成 `std::reference_wrapper<T>`,包装 `obj` 的非 const 引用。 - `std::cref(obj)`:生成 `std::reference_wrapper<const T>`,包装 `obj` 的 const 引用。 --- ### **示例场景** ```cpp #include <functional> #include <vector> #include <algorithm> int main() { int a = 3, b = 1, c = 2; std::vector<std::reference_wrapper<int>> nums{a, b, c}; // 按引用的值排序(直接修改原变量) std::sort(nums.begin(), nums.end(), [](auto x, auto y) { return x.get() < y.get(); // 通过 get() 获取引用 }); // 输出:1 2 3 for (int n : {a, b, c}) std::cout << n << " "; } ``` -- ### **总结** `std::reference_wrapper` 的核心价值是**在需要引用语义但受语言限制的场景中(如容器、模板参数),提供一种轻量级、类型安全的引用包装机制**。其原理是通过内部指针模拟引用,并通过隐式转换保留原生引用的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

等风来不如迎风去

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值