std::reference_wrapper 和简单指针的区别?
为什么需要 std::reference_wrapper代码>?应该在哪里使用?它与简单的指针有何不同?与简单的指针相比,它的性能如何?
Why is there a need to have std::reference_wrapper
? Where should it be used? How is it different from a simple pointer? How its performance compares to a simple pointer?
推荐答案
std::reference_wrapper
与模板结合使用非常有用.它通过存储指向对象的指针来包装对象,允许重新分配和复制,同时模仿其通常的语义.它还指示某些库模板存储引用而不是对象.
std::reference_wrapper
is useful in combination with templates. It wraps an object by storing a pointer to it, allowing for reassignment and copy while mimicking its usual semantics. It also instructs certain library templates to store references instead of objects.
考虑 STL 中复制函子的算法:您可以通过简单地传递引用函子而不是函子本身的引用包装器来避免这种复制:
Consider the algorithms in the STL which copy functors: You can avoid that copy by simply passing a reference wrapper referring to the functor instead of the functor itself:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
这是有效的,因为......
This works because…
…
reference_wrapper
s 重载operator()
所以它们可以像它们引用的函数对象一样被调用:
…
reference_wrapper
s overloadoperator()
so they can be called just like the function objects they refer to:
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()
的调用)应该只是内联,因为它们是单行的.
Copying a reference wrapper is practically equivalent to copying a pointer, which is as cheap as it gets. All the function calls inherent in using it (e.g. the ones to operator()
) should be just inlined as they are one-liners.
reference_wrapper
s 是通过 std::ref
创建的code> 和 std::cref
:
reference_wrapper
s are created via 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-qualification;r2
引用一个 const int
并且只会产生对 const int
的引用.调用包含 const
函子的引用包装器只会调用 const
成员函数 operator()
s.
The template argument specifies the type and cv-qualification of the object referred to; r2
refers to a const int
and will only yield a reference to const int
. Calls to reference wrappers with const
functors in them will only call const
member function operator()
s.
右值初始值设定项是不允许的,因为允许它们弊大于利.由于无论如何都会移动右值(并且使用 保证复制省略即使部分避免了这种情况),我们也不会改进语义;不过,我们可以引入悬空指针,因为引用包装器不会延长指针的生命周期.
Rvalue initializers are disallowed, as permitting them would do more harm than good. Since rvalues would be moved anyway (and with guaranteed copy elision even that's avoided partly), we don't improve the semantics; we can introduce dangling pointers though, as a reference wrapper does not extend the pointee's lifetime.
如前所述,可以通过将相应的参数传递给 reference_wrapper
来指示 make_tuple
在结果 tuple
中存储一个引用:
As mentioned before, one can instruct make_tuple
to store a reference in the resulting tuple
by passing the corresponding argument through a 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
略有不同:这里不允许将右值作为参数.
Note that this slightly differs from forward_as_tuple
: Here, rvalues as arguments are not allowed.
std::bind
显示相同的行为:它如果它是一个 reference_wrapper
,则不会复制参数但存储一个引用.如果该参数(或函子!)不需要复制但在使用 bind
-函子时保持在范围内,则很有用.
std::bind
shows the same behavior: It won't copy the argument but store a reference if it is a reference_wrapper
. Useful if that argument (or the functor!) need not be copied but stays in scope while the bind
-functor is used.
没有额外的语法间接层.指针必须被取消引用以获得指向它们所引用对象的左值;
reference_wrapper
s 有一个隐式的转换运算符并且可以被调用就像它们包裹的物体一样.
There is no additional level of syntactical indirection. Pointers have to be dereferenced to obtain an lvalue to the object they refer to;
reference_wrapper
s have an implicit conversion operator and can be called like the object they wrap.
int i;
int& ref = std::ref(i); // Okay
reference_wrapper
与指针不同,它没有空状态.它们必须使用 引用或另一个 reference_wrapper
.
reference_wrapper
s, unlike pointers, don't have a null state. They have to be initialized with either a reference or another reference_wrapper
.
std::reference_wrapper<int> r; // Invalid
一个相似之处是浅拷贝语义:指针和 reference_wrapper
可以重新分配.
相关文章