哪个更好:返回元组或将参数传递给函数作为引用?

A. *_*zak 7 c++ function

我创建了代码,其中有两个函数returnValuesreturnValuesVoid. 一个返回 2 个值的元组,其他接受参数对函数的引用。

#include <iostream>
#include <tuple>

std::tuple<int, int> returnValues(const int a, const int b) {
    return std::tuple(a,b);
}

void returnValuesVoid(int &a,int &b) {
    a += 100;
    b += 100;
}

int main() {
    auto [x,y] = returnValues(10,20);

    std::cout << x ;
    std::cout << y ;

    int a = 10, b = 20;
    returnValuesVoid(a, b);

    std::cout << a ;
    std::cout << b ;
}
Run Code Online (Sandbox Code Playgroud)

我读到http://en.cppreference.com/w/cpp/language/structured_binding 可以将元组破坏为auto [x,y]变量。

auto [x,y] = returnValues(10,20);不是通过引用传递更好?据我所知,它速度较慢,因为它确实必须返回元组对象,引用仅适用于传递给函数的原始变量,因此除了更干净的代码之外没有理由使用它。

至于auto [x,y]因为C ++ 17中,人们使用它的生产?我看到它看起来比returnValuesVoidvoid 类型更干净,但是它比通过引用传递还有其他优势吗?

Zan*_*Jie 5

看一下反汇编(用GCC -O3编译):

实现元组调用需要更多指令。

0000000000000000 <returnValues(int, int)>:
   0:   83 c2 64                add    $0x64,%edx
   3:   83 c6 64                add    $0x64,%esi
   6:   48 89 f8                mov    %rdi,%rax
   9:   89 17                   mov    %edx,(%rdi)
   b:   89 77 04                mov    %esi,0x4(%rdi)
   e:   c3                      retq   
   f:   90                      nop

0000000000000010 <returnValuesVoid(int&, int&)>:
  10:   83 07 64                addl   $0x64,(%rdi)
  13:   83 06 64                addl   $0x64,(%rsi)
  16:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

但对元组调用者的说明较少:

0000000000000000 <callTuple()>:
   0:   48 83 ec 18             sub    $0x18,%rsp
   4:   ba 14 00 00 00          mov    $0x14,%edx
   9:   be 0a 00 00 00          mov    $0xa,%esi
   e:   48 8d 7c 24 08          lea    0x8(%rsp),%rdi
  13:   e8 00 00 00 00          callq  18 <callTuple()+0x18> // call returnValues
  18:   8b 74 24 0c             mov    0xc(%rsp),%esi
  1c:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  23:   e8 00 00 00 00          callq  28 <callTuple()+0x28> // std::cout::operator<<
  28:   8b 74 24 08             mov    0x8(%rsp),%esi
  2c:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  33:   e8 00 00 00 00          callq  38 <callTuple()+0x38> // std::cout::operator<<
  38:   48 83 c4 18             add    $0x18,%rsp
  3c:   c3                      retq   
  3d:   0f 1f 00                nopl   (%rax)

0000000000000040 <callRef()>:
  40:   48 83 ec 18             sub    $0x18,%rsp
  44:   48 8d 74 24 0c          lea    0xc(%rsp),%rsi
  49:   48 8d 7c 24 08          lea    0x8(%rsp),%rdi
  4e:   c7 44 24 08 0a 00 00    movl   $0xa,0x8(%rsp)
  55:   00 
  56:   c7 44 24 0c 14 00 00    movl   $0x14,0xc(%rsp)
  5d:   00 
  5e:   e8 00 00 00 00          callq  63 <callRef()+0x23> // call returnValuesVoid
  63:   8b 74 24 08             mov    0x8(%rsp),%esi
  67:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  6e:   e8 00 00 00 00          callq  73 <callRef()+0x33> // std::cout::operator<<
  73:   8b 74 24 0c             mov    0xc(%rsp),%esi
  77:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  7e:   e8 00 00 00 00          callq  83 <callRef()+0x43> // std::cout::operator<<
  83:   48 83 c4 18             add    $0x18,%rsp
  87:   c3                      retq   
Run Code Online (Sandbox Code Playgroud)

我不认为有任何显着的性能差异,但元组更清晰,更具可读性。

也尝试过内联调用,绝对没有什么不同。它们都生成完全相同的汇编代码。

0000000000000000 <callTuple()>:
   0:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
   7:   48 83 ec 08             sub    $0x8,%rsp
   b:   be 6e 00 00 00          mov    $0x6e,%esi
  10:   e8 00 00 00 00          callq  15 <callTuple()+0x15>
  15:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  1c:   be 78 00 00 00          mov    $0x78,%esi
  21:   48 83 c4 08             add    $0x8,%rsp
  25:   e9 00 00 00 00          jmpq   2a <callTuple()+0x2a> // TCO, optimized way to call a function and also return
  2a:   66 0f 1f 44 00 00       nopw   0x0(%rax,%rax,1)

0000000000000030 <callRef()>:
  30:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  37:   48 83 ec 08             sub    $0x8,%rsp
  3b:   be 6e 00 00 00          mov    $0x6e,%esi
  40:   e8 00 00 00 00          callq  45 <callRef()+0x15>
  45:   48 8d 3d 00 00 00 00    lea    0x0(%rip),%rdi
  4c:   be 78 00 00 00          mov    $0x78,%esi
  51:   48 83 c4 08             add    $0x8,%rsp
  55:   e9 00 00 00 00          jmpq   5a <callRef()+0x2a> // TCO, optimized way to call a function and also return
Run Code Online (Sandbox Code Playgroud)