在将 std::minmax
与结构化绑定(bind)一起使用时,我遇到了一个相当微妙的错误。似乎传递的右值并不总是像预期的那样被复制。最初我在自定义容器上使用 T operator[]() 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
}
使用带有 -O1 -Wuninitialized
的 GCC 8.1.1 将导致 0,0
被打印为第一行并且:
warning: ‘<anonymous>’ is used uninitialized in this function [-Wuninitialized]
-O2
的 Clang 6.0.1 也会给出错误的第一个结果而没有警告。
在 -O0
处,GCC 给出了正确的结果并且没有警告。对于 clang,结果在 -O1
或 -O0
处似乎是正确的。
第一行和第二行不应该是等价的,因为右值仍然可以被复制吗?
另外,为什么这取决于优化级别?特别令我惊讶的是 GCC 没有发出警告。
最佳答案
auto [amin, amax]
中的重要注意事项是auto
, auto&
等等被应用到组成的对象 e
用返回值 std::minmax
初始化,这是一对。本质上是这样的:
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
时,您正在对现有对象进行分配(通过引用传递)。右值不需要比它们产生的赋值表达式的生命周期更长。
作为一种解决方法,您可以使用类似这样的功能(不是生产质量):
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));
我们现在得到一个拷贝,结构化绑定(bind)引用这些拷贝。
关于c++ - 具有 std::minmax 和右值的结构化绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51503114/