init语句中临时std::tuple的开销
Overhead of temporary std::tuple in init statement
我在各种情况下使用 std::tuple
s 并发现了一些有用的东西,但我不确定它们是否会降低性能。
在 C++17 中,为 if
和 switch
语句引入了一个 init 语句。为了定义多个不同类型的变量,您可以使用临时元组和结构化绑定。
if(const auto& [x, y] = std::tuple{some_expensive_int_calculation(), get_string_message()}; x != 0 && y != "") {
std::cout << "X is " << x << ", message equals " << y << std::endl;
}
这个应该不会有很大的性能损失,如果有的话。当然,它会创建一个元组,它本身比类型本身需要更多的内存,但这是在堆栈上分配的,所以再一次,它不应该真的有那么大的伤害。绑定 x
和 y
在编译时而不是在运行时解析,所以这似乎是一个没有大的运行时惩罚的解决方案,是吗?
编辑:更新示例以防止编译器对元组进行微不足道的优化并使问题更加清晰。
在给定的示例中,编译器很容易证明不为 x
分配或分配存储与分配和测试 x
具有相同的结果。因此,在启用优化的情况下,我希望它能在生成的汇编程序中省略对 x
的任何提及。
确实,使用 gcc 7.3 -O2
,以下程序:
#include <tuple>
#include <iostream>
int main()
{
if(const auto& [x, y] = std::tuple{0, "Test"}; x == 0) {
std::cout << y << std::endl;
}
}
变成:
main:
# stack-frame related code
sub rsp, 8
# get address of "Test" string
mov esi, OFFSET FLAT:.LC0
# get address of std::cout
mov edi, OFFSET FLAT:std::cout
# call operator <<
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
# move returned ostream reference to rdi (arg1)
mov rdi, rax
# and call std::endl
call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
# return 0
xor eax, eax
# clean up stack and return
add rsp, 8
ret
请注意,此汇编程序输出中没有任何地方提到 x。也确实没有提到元组或条件分支。
"as if" 规则允许这样做。
我在各种情况下使用 std::tuple
s 并发现了一些有用的东西,但我不确定它们是否会降低性能。
在 C++17 中,为 if
和 switch
语句引入了一个 init 语句。为了定义多个不同类型的变量,您可以使用临时元组和结构化绑定。
if(const auto& [x, y] = std::tuple{some_expensive_int_calculation(), get_string_message()}; x != 0 && y != "") {
std::cout << "X is " << x << ", message equals " << y << std::endl;
}
这个应该不会有很大的性能损失,如果有的话。当然,它会创建一个元组,它本身比类型本身需要更多的内存,但这是在堆栈上分配的,所以再一次,它不应该真的有那么大的伤害。绑定 x
和 y
在编译时而不是在运行时解析,所以这似乎是一个没有大的运行时惩罚的解决方案,是吗?
编辑:更新示例以防止编译器对元组进行微不足道的优化并使问题更加清晰。
在给定的示例中,编译器很容易证明不为 x
分配或分配存储与分配和测试 x
具有相同的结果。因此,在启用优化的情况下,我希望它能在生成的汇编程序中省略对 x
的任何提及。
确实,使用 gcc 7.3 -O2
,以下程序:
#include <tuple>
#include <iostream>
int main()
{
if(const auto& [x, y] = std::tuple{0, "Test"}; x == 0) {
std::cout << y << std::endl;
}
}
变成:
main:
# stack-frame related code
sub rsp, 8
# get address of "Test" string
mov esi, OFFSET FLAT:.LC0
# get address of std::cout
mov edi, OFFSET FLAT:std::cout
# call operator <<
call std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
# move returned ostream reference to rdi (arg1)
mov rdi, rax
# and call std::endl
call std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)
# return 0
xor eax, eax
# clean up stack and return
add rsp, 8
ret
请注意,此汇编程序输出中没有任何地方提到 x。也确实没有提到元组或条件分支。
"as if" 规则允许这样做。