为什么需要std::reference_wrapper
?应该在哪里使用?它与简单的指针有何不同?它的性能与简单指针相比如何?
最佳答案
std::reference_wrapper
与模板结合使用很有用。它通过存储指向对象的指针来包装对象,允许在模仿其通常语义的同时重新分配和复制。它还指示某些库模板存储引用而不是对象。
考虑 STL 中复制仿函数的算法:您可以通过简单地传递引用仿函数而不是仿函数本身的引用包装来避免该复制:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
这行得通,因为……
…
reference_wrapper
s overloadoperator()
所以它们可以像它们引用的函数对象一样被调用:std::ref(myEngine)() // Valid expression, modifies myEngines state
...(un) 与普通引用一样,复制(和分配)
reference_wrappers
只是分配指针。int i, j; auto r = std::ref(i); // r refers to i r = std::ref(j); // Okay; r refers to j r = std::cref(j); // Error: Cannot bind reference_wrapper<int> to <const int>
复制一个引用包装器实际上等同于复制一个指针,这是尽可能便宜的。使用它时固有的所有函数调用(例如 operator()
的函数调用)应该只是内联,因为它们是单行的。
reference_wrapper
是通过 std::ref
and std::cref
创建的:
int i;
auto r = std::ref(i); // r is of type std::reference_wrapper<int>
auto r2 = std::cref(i); // r is of type std::reference_wrapper<const int>
模板参数指定所引用对象的类型和 cv 限定; r2
引用 const int
并且只会产生对 const int
的引用。调用包含 const
仿函数的引用包装器只会调用 const
成员函数 operator()
s。
不允许使用右值初始化器,因为允许它们弊大于利。由于无论如何都会移动右值(并且使用 guaranteed copy elision,即使部分避免了),我们不改进语义;不过我们可以引入悬空指针,因为引用包装器不会延长指针的生命周期。
图书馆互动
如前所述,可以指示 make_tuple
将引用存储在生成的 tuple
中,方法是通过 reference_wrapper
传递相应的参数:
int i;
auto t1 = std::make_tuple(i); // Copies i. Type of t1 is tuple<int>
auto t2 = std::make_tuple(std::ref(i)); // Saves a reference to i.
// Type of t2 is tuple<int&>
请注意,这与 forward_as_tuple
略有不同:此处不允许将右值作为参数。
std::bind
显示相同的行为:如果它是 reference_wrapper
,它不会复制参数但存储引用。如果该参数(或仿函数!)不需要复制但在使用 bind
-仿函数时保持在范围内,则很有用。
与普通指针的区别
没有额外的语法间接层。必须取消引用指针才能获得指向它们所引用对象的左值;
reference_wrapper
有一个隐含的 conversion operator并且可以像它们包装的对象一样被调用。int i; int& ref = std::ref(i); // Okay
reference_wrapper
与指针不同,没有空状态。它们必须用 either a reference or anotherreference_wrapper
初始化.std::reference_wrapper<int> r; // Invalid
相似之处是浅拷贝语义:指针和
reference_wrapper
可以重新分配。
关于c++ - std::reference_wrapper 和简单指针有什么区别?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26766939/