gpt4 book ai didi

c++ - std::get 在右值引用元组上的行为是否危险?

转载 作者:可可西里 更新时间:2023-11-01 18:38:17 24 4
gpt4 key购买 nike

以下代码:

#include <tuple>

int main ()
{
auto f = [] () -> decltype (auto)
{
return std::get<0> (std::make_tuple (0));
};

return f ();
}

(静默地)生成具有未定义行为的代码 - make_tuple 返回的临时右值通过 std::get<> 和 decltype(auto) 传播到返回类型。所以它最终会返回对超出范围的临时对象的引用。在这里查看 https://godbolt.org/g/X1UhSw .

现在,您可能会争辩说我对 decltype(auto) 的使用是错的。但是在我的通用代码中(元组的类型可能是 std::tuple<Foo &> )我不想总是制作拷贝。我真的很想从元组中提取确切的值或引用。

我的感觉是 std::get 的重载很危险:

template< std::size_t I, class... Types >
constexpr std::tuple_element_t<I, tuple<Types...> >&&
get( tuple<Types...>&& t ) noexcept;

虽然将左值引用传播到元组元素上可能是明智的,但我认为这不适用于右值引用。

我相信标准委员会非常仔细地考虑过这个问题,但是谁能向我解释为什么这被认为是最佳选择吗?

最佳答案

考虑以下示例:

void consume(foo&&);

template <typename Tuple>
void consume_tuple_first(Tuple&& t)
{
consume(std::get<0>(std::forward<Tuple>(t)));
}

int main()
{
consume_tuple_first(std::tuple{foo{}});
}

在这种情况下,我们知道 std::tuple{foo{}}是临时的,它将在 consume_tuple_first(std::tuple{foo{}}) 的整个持续时间内存在表达。

我们希望避免任何不必要的复制和移动,但仍传播 foo{} 的临时性至 consume .

唯一的方法是使用 std::get使用临时 std::tuple 调用时返回一个右值引用实例。

live example on wandbox


改变 std::get<0>(std::forward<Tuple>(t))std::get<0>(t)产生编译错误(如预期的那样)(on wandbox)。


有一个 get按值返回的替代方案会导致额外的不必要的移动:

template <typename Tuple>
auto myget(Tuple&& t)
{
return std::get<0>(std::forward<Tuple>(t));
}

template <typename Tuple>
void consume_tuple_first(Tuple&& t)
{
consume(myget(std::forward<Tuple>(t)));
}

live example on wandbox


but can anyone explain to me why this was considered the best option?

因为它启用了可选的通用代码,可以在访问元组时无缝传播临时右值引用。按值返回的替代方法可能会导致不必要的移动操作。

关于c++ - std::get 在右值引用元组上的行为是否危险?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47905333/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com