当使用std :: minmax和结构化绑定时,我遇到了一个相当微妙的错误.似乎传递的rvalues并不总是像人们期望的那样被复制.最初我在自定义容器上使用了T运算符[]()const,但它似乎与文字整数相同.
#include <algorithm>
#include <cstdio>
#include <tuple>
int main()
{
auto [amin, amax] = std::minmax(3, 6);
printf("%d,%d\n", amin, amax); // undefined,undefined
int bmin, bmax;
std::tie(bmin, bmax) = std::minmax(3, 6);
printf("%d,%d\n", bmin, bmax); // 3,6
}
将GCC 8.1.1与-O1 -Wuninitialized一起使用将导致0,0作为第一行打印,并且:
warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
Clang 6.0.1 at -O2也会在没有警告的情况下给出错误的第一个结果.
在-O0 GCC给出正确的结果而没有警告.对于clang,结果在-O1或-O0处显示正确.
在rvalue仍然有效被复制的意义上,第一行和第二行不应该是等价的吗?
另外,为什么这取决于优化级别?特别是我对GCC没有发出任何警告感到惊讶.
解决方法:
在auto [amin,amax]中需要注意的重要一点是auto,auto和amp;等等应用于用std :: minmax的返回值初始化的组成对象e,它是一对.它基本上是这样的:
auto e = std::minmax(3, 6);
auto&& amin = std::get<0>(e);
auto&& amax = std::get<1>(e);
amin和amax的实际类型是引用任何std :: get< 0>的引用.和std :: get< 1>返回该对象对象.并且他们自己返回对已经过去的对象的引用!
当您使用std :: tie时,您正在对现有对象进行赋值(通过引用传递). rvalues不需要比它们产生的赋值表达式更长寿.
作为一种解决方法,你可以使用这样的东西(不是生产质量)功能:
template<typename T1, typename T2>
auto as_value(std::pair<T1, T2> in) {
using U1 = std::decay_t<T1>;
using U2 = std::decay_t<T2>;
return std::pair<U1, U2>(in);
}
它确保该对保持值类型.当像这样使用时:
auto [amin, amax] = as_value(std::minmax(3, 6));
我们现在得到一份副本,结构化绑定指的是那些副本.