boost::reference_wrapper<T>
有一个 显式 T&
构造函数,而 std::reference_wrapper<T>
有一个 隐式 一。因此,在以下代码中:
foo = bar;
如
foo
是 boost::reference_wrapper
,代码将无法编译(这很好,因为 reference_wrapper
确实 而不是 具有与实际引用相同的语义。如
foo
是 std::reference_wrapper
,代码将“重新绑定(bind)”foo
引用 bar
(而不是像人们可能错误地期望的那样分配值)。这可能会导致难以捉摸的错误......考虑以下示例:
在版本 1.0 一些假设的图书馆:
void set_max(int& i, int a, int b) {
i = (a > b) ? a : b;
}
在新版本 ( 1.1 ) 中,
set_max
转换为模板以接受任何宽度(或 UDT)的整数,而无需更改接口(interface):template<typename T1, typename T2, typename T3>
void set_max(T1& i, T2 a, T3 b) {
i = (a > b) ? a : b;
}
最后,在一些使用库的应用程序中:
// i is a std::reference_wrapper<int> passed to this template function or class
set_max(i, 7, 11);
在这个例子中,库改变了它的实现
set_max
在不改变通话界面的情况下。这会悄悄地破坏任何传递给它的代码 std::reference_wrapper
因为参数将不再转换为 int&
而是“重新绑定(bind)”到悬空引用( a
或 b
)。我的问题:为什么标准委员会选择允许隐式转换(从
T&
到 std::reference_wrapper<T>
)而不是遵循 boost
并制作 T&
构造函数显式?编辑: (回应乔纳森·韦克利(Jonathan Wakely)提供的答案)...
原始演示(在上一节中)有意简洁地展示了微妙的库更改如何导致使用
std::reference_wrapper
将错误引入应用程序。提供下一个演示以展示
reference_wrapper
的真实合法使用。用于“通过接口(interface)传递引用”,以回应 Jonathan Wakely 的观点。类似于
std::bind
但假设它专门用于某些任务:template<typename FuncType, typename ArgType>
struct MyDeferredFunctionCall
{
MyDeferredFunctionCall(FuncType _f, ArgType _a) : f(_f), a(_a) {}
template<typename T>
void operator()(T t) { f(a, t); }
FuncType f;
ArgType a;
};
一个
RunningMax
仿函数类。在这个虚构库的 1.0 和 1.1 版本之间,RunningMax
的实现更改为更通用,而不更改其调用接口(interface)。 出于本演示的目的 ,旧的实现定义在命名空间 lib_v1
中,而新的实现在 lib_v2
中定义:namespace lib_v1 {
struct RunningMax {
void operator()(int& curMax, int newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
namespace lib_v2 {
struct RunningMax {
template<typename T1, typename T2>
void operator()(T1& curMax, T2 newVal) {
if ( newVal > curMax ) { curMax = newVal; }
}
};
}
一些开发人员使用供应商/开发人员 A 和 B 的代码来完成一些任务:
int main() {
int _i = 7;
auto i = std::ref(_i);
auto f = lib_v2::RunningMax{};
using MyDFC = MyDeferredFunctionCall<decltype(f), decltype(i)>;
MyDFC dfc = MyDFC(f, i);
dfc(11);
std::cout << "i=[" << _i << "]" << std::endl; // should be 11
}
请注意以下事项:
std::reference_wrapper
它的预期方式。 valgrind
之类的工具的内存错误。会捕获。此外,实际网站的滥用std::reference_wrapper
将在供应商内 乙 的库代码,而不是最终用户的。 底线:
boost::reference_wrapper
通过声明它的 T&
似乎更安全构造函数作为显式,并会防止引入这样的错误。决定在 std::reference_wrapper
中删除显式构造函数限制似乎为了方便而损害了安全性,这在语言/库设计中应该很少发生。
最佳答案
This would silently break any code that passes it a
std::reference_wrapper
as the argument would no longer convert toint&
and would instead "rebind" to a dangling reference (a or b).
所以不要那样做。
reference_wrapper
用于通过接口(interface)传递引用,否则会进行按值复制,而不是传递给任意代码。还:
// i is a std::reference_wrapper<int> (perhaps b/c std::decay wasn't used)
decay
不会改变任何东西,它不会影响引用包装器。
关于c++ - std::reference_wrapper<T> 的隐式 T& 构造函数是否会使使用变得危险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15646681/