Lau*_*kas 83 c++ pointers reference c++11 reference-wrapper
为什么需要std::reference_wrapper
?应该在哪里使用?它与简单的指针有什么不同?它的性能与简单的指针相比如何?
Col*_*mbo 82
std::reference_wrapper
与模板结合使用非常有用.它通过存储指向它的指针来包装对象,允许重新分配和复制,同时模仿其通常的语义.它还指示某些库模板存储引用而不是对象.
考虑STL中复制仿函数的算法:您可以通过简单地传递引用包装器而不是仿函数本身来避免该副本:
unsigned arr[10];
std::mt19937 myEngine;
std::generate_n( arr, 10, std::ref(myEngine) ); // Modifies myEngine's state
Run Code Online (Sandbox Code Playgroud)
这是因为......
... reference_wrapper
s 重载,operator()
因此可以像调用它们的函数对象一样调用它们:
std::ref(myEngine)() // Valid expression, modifies myEngines state
Run Code Online (Sandbox Code Playgroud)...(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>
Run Code Online (Sandbox Code Playgroud)复制引用包装器实际上相当于复制指针,这种指针虽然便宜.使用它所固有的所有函数调用(例如,那些函数调用operator()
)应该只是内联,因为它们是单行的.
reference_wrapper
s的通过创建std::ref
和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>
Run Code Online (Sandbox Code Playgroud)
template参数指定所引用对象的类型和cv限定条件; r2
指的是a const int
并且只会引用const int
.调用带有const
仿函数的包装器的调用只会调用const
成员函数operator()
.
Rvalue初始化器是不允许的,因为允许它们弊大于利.由于rvalues无论如何都会被移动(并且有保证的复制省略,即使部分避免了),我们也不会改进语义; 我们可以引入悬空指针,因为引用包装器不会延长指针的生命周期.
如前所述,可以通过以下方式传递相应的参数来指示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&>
Run Code Online (Sandbox Code Playgroud)
请注意,这与forward_as_tuple
以下略有不同:此处,不允许使用rvalues作为参数.
std::bind
显示相同的行为:它不会复制参数,但如果它是a,则存储引用reference_wrapper
.如果不需要复制该参数(或bind
仿函数!),但在使用-functor时保持在范围内,则非常有用.
没有额外的语法间接层次.指针必须被解除引用才能获得它们所指对象的左值; reference_wrapper
s有一个隐式转换运算符,可以像它们包装的对象一样调用.
int i;
int& ref = std::ref(i); // Okay
Run Code Online (Sandbox Code Playgroud)reference_wrapper
s,与指针不同,没有null状态.它们必须使用引用或其他引用reference_wrapper
进行初始化.
std::reference_wrapper<int> r; // Invalid
Run Code Online (Sandbox Code Playgroud)相似性是浅拷贝语义:reference_wrapper
可以重新分配指针和s.
Die*_*ühl 24
至少有两个激励目的std::reference_wrapper<T>
:
它是为作为值参数传递给函数模板的对象提供引用语义.例如,您可能有一个想要传递给std::for_each()
它的大型函数对象,它通过值获取其函数对象参数.为避免复制对象,您可以使用
std::for_each(begin, end, std::ref(fun));
Run Code Online (Sandbox Code Playgroud)
通过引用而不是通过值std::reference_wrapper<T>
来传递参数来传递关于std::bind()
表达式的参数是很常见的.
当使用std::reference_wrapper<T>
带有std::make_tuple()
相应元组元素的元素变成T&
而不是T
:
T object;
f(std::make_tuple(1, std::ref(object)));
Run Code Online (Sandbox Code Playgroud)Bar*_*rry 19
您可以将其视为引用的便利包装器,以便您可以在容器中使用它们.
std::vector<std::reference_wrapper<T>> vec; // OK - does what you want
std::vector<T&> vec2; // Nope! Will not compile
Run Code Online (Sandbox Code Playgroud)
它基本上是一个CopyAssignable
版本T&
.任何时候你想要一个引用,但它必须是可分配的,使用std::reference_wrapper<T>
或其辅助函数std::ref()
.或者使用指针.
其他怪癖sizeof
:
sizeof(std::reference_wrapper<T>) == sizeof(T*) // so 8 on a 64-bit box
sizeof(T&) == sizeof(T) // so, e.g., sizeof(vector<int>&) == 24
Run Code Online (Sandbox Code Playgroud)
比较:
int i = 42;
assert(std::ref(i) == std::ref(i)); // ok
std::string s = "hello";
assert(std::ref(s) == std::ref(s)); // compile error
Run Code Online (Sandbox Code Playgroud)
Edw*_*per 19
就自我记录代码而言,另一个区别在于使用reference_wrapper
基本上否定对象的所有权.相反,unique_ptr
断言所有权,而裸指针可能拥有或不拥有(如果不查看大量相关代码,则无法知道):
vector<int*> a; // the int values might or might not be owned
vector<unique_ptr<int>> b; // the int values are definitely owned
vector<reference_wrapper<int>> c; // the int values are definitely not owned
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
29581 次 |
最近记录: |