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

在std::promise范例中,使用了std::ref将future对象传递给引用参数类型的任务函数。

std::promise示例

如果直接传入pr,将会出现编译错误:

error C2661: “std::tuple,std::promise>::tuple”: 没有重载函数接受 2 个参数

说明函数调用的参数类型不匹配。

查看thread的源代码,其构造函数依赖于一个rvalue-reference类型的variaic templates参数列表:

template::type, thread>::value>::type>explicit
thread(_Fn&& _Fx, _Args&&... _Ax){
    // construct with _Fx(_Ax...)
    _Launch(&_Thr,
        _STD make_unique, decay_t<_Args>...> >(
            _STD forward<_Fn>(_Fx), _STD forward<_Args>(_Ax)...));
}

其中的“_Args&&... _Ax”也是C++11引入的新特性:Variadic templates,它允许函数可以接受任意个不同类型的参数,类似于C语言中的可变参数。在参考文档[4]中说,”However, thanks to variadic templates, programming new features using templates has become easier, clearer & more memory-efficient.“,为什么内存效率更高呢?参考[6]中解释说:参数列表所形成的一个parameter pack在编译期间被解包,C++利用编译期的处理实现了运行时效率优化。参考[5]中说:”Variadic templates are a trustworthy solution to implement delegates and tuples. And, instead of C-style ellipsis mechanism, variadic templates can offer a typesafer solution to replace them.“具体如何实现delegates和tuples,另行描述。

除了可变模板,另外两个相关的新技术是rvalue-reference和reference_wrapper,这两者和move语义是紧密相连的,如此节省了很多右值对象的复制构造开销。

std::ref(pr)返回的对象类型是一个reference_wrapper,而不是对pr的直接引用(T&,即std::promise&)。

换一个参考[7]中的例子:


C++11为什么需要std::ref/reference_wrapper?_第1张图片
bind与reference_wrapper的示例第一部分

上述代码的结果是0!为什么?因为bind方法通过传值方式传入参数,在被传递给绑定目标add方法之前,变量”result“已经被重新拷贝了。因为bind必须确保传入的参数是持续可用的。

解决方法很简单,使用reference_wrapper:

C++11为什么需要std::ref/reference_wrapper?_第2张图片
bind与reference_wrapper的示例第二部分

使用如下代码定义reference_wrapper对象:

 reference_wrapper r=x;// or auto r = ref(x); 

通过r对象的get函数(r.get()),r的作用与直接引用完全一样。

还可以用来创建引用数组,例如:

引用数组的创建

std::reference_wrapper在泛型代码中用处广泛,它存储的是对象的指针,有引用的全部功能,还实现了引用的拷贝(包括拷贝构造和拷贝赋值),可以在程序中存储引用而不是整个对象。

reference_wrapper和shared_ptr如何选择?两者都可以实现指针层面的复制和操作,但是前者不允许默认构造函数,在容器中也不能使用resize等方法。另外可能还有一些不同之处,但是基本上没有太大区别了。



参考资料:

[1] http://stackoverflow.com/questions/33240993/c-difference-between-stdreft-and-t
[2] http://stackoverflow.com/questions/26766939/difference-between-stdreference-wrapper-and-simple-pointer
[3] http://stackoverflow.com/questions/31013689/why-does-stdthread-take-function-to-run-by-rvalue
[4] http://softwareengineering.stackexchange.com/questions/273448/polymorphic-template-container-shared-ptr-vs-reference-wrapper
[5] http://www.cplusplus.com/articles/EhvU7k9E/
[6] Real-Time C++: Efficient Object-Oriented and Template Microcontroller Programming, 2015-12,Christopher Kormanyos
[7] https://oopscenities.net/2012/08/09/reference_wrapper/

你可能感兴趣的:(C++11为什么需要std::ref/reference_wrapper?)