加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 返回std :: pair与非const引用的传递

发布时间:2020-12-16 10:54:14 所属栏目:百科 来源:网络整理
导读:为什么返回std :: pair或boost :: tuple比通过引用返回效率低得多?在我测试的实际代码中,通过非const引用而不是内核中的std :: pair设置数据可以将代码加速20%. 作为一个实验,我查看了三个最简单的情况,包括将两个(预定义的)整数添加到两个整数: 使用内部
为什么返回std :: pair或boost :: tuple比通过引用返回效率低得多?在我测试的实际代码中,通过非const引用而不是内核中的std :: pair设置数据可以将代码加速20%.

作为一个实验,我查看了三个最简单的情况,包括将两个(预定义的)整数添加到两个整数:

>使用内部内联函数通过引用修改整数
>使用两个内部内联函数按值返回整数
>使用内部内联函数返回复制到结果的std :: pair.

使用g -c $x -Wall -Wextra -O2 -S进行编译会产生相同的汇编代码,以便按引用传递并按值返回int:

__Z7getPairiRiS_:
LFB19:
    pushq   %rbp
LCFI0:
    leal    1023(%rdi),%eax
    addl    $31,%edi
    movl    %eax,(%rsi)
    movq    %rsp,%rbp
LCFI1:
    movl    %edi,(%rdx)
    leave
    ret

(通过参考代码:

#include <utility>

inline void myGetPair(const int inp,int& a,int& b) {
    a = 1023 + inp;
    b = 31 + inp;
}

void getPair(const int inp,int& b) {
    myGetPair(inp,a,b);
}

使用单独的右值:

#include <utility>

inline int myGetPair1(int inp) {
    return 1023 + inp;
}

inline int myGetPair2(int inp) {
    return 31 + inp;
}

void getPair(const int inp,int& b) {
    a = myGetPair1(inp);
    b = myGetPair2(inp);
}

)

但是,使用std :: pair会添加五个额外的汇编语句:

__Z7getPairiRiS_:
LFB18:
    leal    31(%rdi),%eax
    addl    $1023,%edi
    pushq   %rbp
LCFI0:
    salq    $32,%rax
    movq    %rsp,%rbp
LCFI1:
    orq %rdi,%rax
    movq    %rax,%rcx
    movl    %eax,(%rsi)
    shrq    $32,%rcx
    movl    %ecx,(%rdx)
    leave
    ret

其代码几乎与前面的示例一样简单:

#include <utility>

inline std::pair<int,int> myGetPair(int inp) {
    return std::make_pair(1023 + inp,31 + inp);
}

void getPair(const int inp,int& b) {
    std::pair<int,int> result = myGetPair(inp);

    a = result.first;
    b = result.second;
}

任何知道编译器内部工作原理的人都可以帮助解决这个问题吗? boost tuple page引用了元组与传递引用的性能损失,但没有一个链接的文章回答这个问题.

我更喜欢std :: pair到这些pass-by-reference语句的原因是它使得函数的意图在许多情况下更加清晰,特别是当输入其他参数以及要修改的参数时.

解决方法

我尝试使用VC 2008,使用cl.exe / c / O2 / FAs foo.cpp(即“仅编译并且不链接”,“优化速度”和“在注释中使用匹配的源代码行转储汇编输出”) ).以下是getLine()最终的结果.

“byref”版本:

PUBLIC  ?getPair@@YAXHAAH0@Z                ; getPair
; Function compile flags: /Ogtpy
;   COMDAT ?getPair@@YAXHAAH0@Z
_TEXT   SEGMENT
_inp$= 8                       ; size = 4
_a$= 12                        ; size = 4
_b$= 16                        ; size = 4
?getPair@@YAXHAAH0@Z PROC               ; getPair,COMDAT

; 9    :     myGetPair(inp,b);

    mov eax,DWORD PTR _inp$[esp-4]
    mov edx,DWORD PTR _a$[esp-4]
    lea ecx,DWORD PTR [eax+1023]
    mov DWORD PTR [edx],ecx
    mov ecx,DWORD PTR _b$[esp-4]
    add eax,31                 ; 0000001fH
    mov DWORD PTR [ecx],eax

; 10   : }

    ret 0
?getPair@@YAXHAAH0@Z ENDP               ; getPair

“byval”std :: pair-returning版本:

PUBLIC  ?getPair@@YAXHAAH0@Z                ; getPair
; Function compile flags: /Ogtpy
;   COMDAT ?getPair@@YAXHAAH0@Z
_TEXT   SEGMENT
_inp$= 8                       ; size = 4
_a$= 12                        ; size = 4
_b$= 16                        ; size = 4
?getPair@@YAXHAAH0@Z PROC               ; getPair,COMDAT

; 8    :     std::pair<int,int> result = myGetPair(inp);

    mov eax,DWORD PTR _inp$[esp-4]

; 9    : 
; 10   :     a = result.first;

    mov edx,ecx

; 11   :     b = result.second;

    mov ecx,eax

; 12   : }

    ret 0
?getPair@@YAXHAAH0@Z ENDP               ; getPair

如您所见,实际装配是相同的;唯一的区别在于错误的名称和评论.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读