为什么返回 std::pair 或 boost::tuple 比通过引用返回效率低得多?在我测试过的实际代码中,通过非常量引用而不是通过内部内核中的 std::pair 设置数据可以将代码速度提高 20%。
作为实验,我研究了三个最简单的情况,涉及将两个(预定义的)整数与两个整数相加:
使用内部内联函数通过引用修改整数
使用两个内部的内联函数按值返回整数
使用一个内部的内联函数返回一个 std::pair,它被复制到结果中。
使用 g++ -c $x -Wall -Wextra -O2 -S 编译会产生相同的汇编代码,用于按引用传递和按值返回整数:
__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& a, 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& a, 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& a, int& b) {
std::pair<int,int> result = myGetPair(inp);
a = result.first;
b = result.second;
}
谁知道编译器的内部工作原理可以帮助解决这个问题吗? boost tuple page提到了元组与按引用传递的性能损失,但没有一篇链接的论文回答了这个问题。
与这些传递引用语句相比,我更喜欢 std::pair 的原因是它使函数的意图much 在许多情况下更加清晰,尤其是当其他参数输入为以及要修改的那些。
最佳答案
我用 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, a, 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-返回版本:
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, DWORD PTR _a$[esp-4]
lea ecx, DWORD PTR [eax+1023]
mov DWORD PTR [edx], ecx
; 11 : b = result.second;
mov ecx, DWORD PTR _b$[esp-4]
add eax, 31 ; 0000001fH
mov DWORD PTR [ecx], eax
; 12 : }
ret 0
?getPair@@YAXHAAH0@Z ENDP ; getPair
如您所见,实际的 assembly 是相同的;唯一的区别在于名称和注释的困惑。
关于c++ - 返回 std::pair 与通过非常量引用传递,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1869171/
尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我正在使用puppet为ruby程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这
我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是
我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search
我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案
有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题: