引用包装器
std::reference_wrapper
是 C++ 标准库 <functional>
头文件中的一个类模板,它的主要作用是将引用包装成一个可拷贝、可赋值的对象。
1. 什么是 std::reference_wrapper
?
在 C++ 中,引用(reference)本身不能被重新赋值,也不能作为容器的元素,因为它们不符合大多数标准库容器和算法对**可拷贝(Copyable)或可赋值(Assignable)**的要求。
std::reference_wrapper<T>
解决了这个问题。它内部持有一个 T
类型的引用,但它本身是一个对象,可以像普通对象一样被拷贝和赋值。当你拷贝一个 std::reference_wrapper
对象时,你拷贝的是对同一个原始对象的引用,而不是拷贝原始对象本身。
2. 为什么需要它?
std::reference_wrapper
的主要用途是让引用能够与标准库容器和算法协同工作。
许多标准库组件,比如 std::vector
、std::list
、std::thread
、std::sort
等,要求其操作的对象是可拷贝的。如果你直接尝试将引用放入这些容器或传递给这些函数,编译器会报错。
例如,下面的代码无法编译,因为 std::vector
不允许存储引用:
1 | // 错误示例:不能直接存储引用 |
通过使用 std::reference_wrapper
,你可以绕过这个限制,将引用“伪装”成一个可存储在容器中的对象:
1 |
|
std::ref
和 std::cref
辅助函数:
为了方便使用,C++ 标准库提供了两个辅助函数:
std::ref(T& obj)
:创建一个std::reference_wrapper<T>
对象。std::cref(const T& obj)
:创建一个std::reference_wrapper<const T>
对象,用于常量引用。
3. std::reference_wrapper
的常见用途
容器存储引用: 如上例所示,将引用放入
std::vector
、std::map
等容器中。多线程传递可变对象: 当使用
std::thread
启动新线程时,如果你希望线程函数能够修改一个外部变量,你需要通过std::ref
传递引用。直接传递变量会发生拷贝。泛型编程与算法: 在使用如
std::bind
或std::sort
等算法时,如果你想让它们操作原始对象而不是拷贝,std::reference_wrapper
是一个重要的工具。
例子:std::sort
的应用
假设你有一个自定义对象的向量,你想根据其中一个成员变量对它们进行排序,但你不想拷贝整个对象。你可以创建一个存储 std::reference_wrapper
的向量来对原始对象进行间接排序。
1 |
|
总结:
std::reference_wrapper
是一种“引用对象”,它解决了 C++ 中引用不能被拷贝、不能被赋值、不能作为容器元素的问题。它的核心价值在于让引用能够无缝地融入 C++ 标准库的容器和算法生态系统,从而在需要传递引用而非拷贝时提供了强大的支持。