Common wisdom is that std::unique_ptr does not introduce a performance penalty ( and not a memory penalty when not using a deleter parameter ),但我最近偶然发现了一个讨论,该讨论表明它实际上引入了一个额外的间接寻址,因为 unique_ptr 无法在具有 Itanium ABI 的平台上的寄存器中传递。发布的示例类似于
#include <memory>
int foo(std::unique_ptr<int> u) {
return *u;
}
int boo(int* i) {
return *i;
}
Which generates an additional assembler instruction in foo compared to boo.
foo(std::unique_ptr<int, std::default_delete<int> >):
mov rax, QWORD PTR [rdi]
mov eax, DWORD PTR [rax]
ret
boo(int*):
mov eax, DWORD PTR [rdi]
ret
解释是 Itanium ABI 要求 unique_ptr 不应该在寄存器中传递,因为非平凡的构造函数,所以它在堆栈上创建,然后这个对象的地址是在寄存器中传递。
我知道这不会真正影响现代 PC 平台的性能,但我想知道是否有人可以提供更多详细信息,说明为什么不能将其复制到寄存器中。由于零成本抽象是 C++ 的主要目标之一,我想知道这是否已在标准化过程中作为可接受的偏差进行讨论,或者它是否是实现质量问题。考虑到好处时,性能损失肯定足够小,尤其是在现代 PC 平台上。
评论者指出这两个函数并不完全等价,因此比较存在缺陷,因为 foo 也会调用 unique_ptr 参数上的删除器,但是 boo 不释放内存。但是,我只对按值传递 unique_ptr 与传递普通指针所产生的差异感兴趣。 I've modified the example code and included a call to delete to free the plain pointer ;调用在调用者中,因为 unique_ptr 的删除器也在调用者的上下文中被调用,以使生成的代码更加相同。此外,手动delete 还会检查ptr != nullptr,因为析构函数也会这样做。不过,foo 不会在寄存器中传递参数,必须
进行间接访问。
我还想知道为什么编译器在调用 operator delete 之前不省略对 nullptr 的检查,因为这无论如何都被定义为空操作。我猜 unique_ptr 可以专门用于默认删除器,不在析构函数中执行检查,但这将是一个非常小的微优化。
最佳答案
System V ABI 使用 Itanium C++ ABI 并引用它。特别是,C++ Itanium ABI指定
If the parameter type is non-trivial for the purposes of calls, the caller must allocate space for a temporary and pass that temporary by reference.
Specifically:
...
If the type has a non-trivial destructor, the caller calls that destructor after control returns to it (including when the caller throws an exception), at the end of enclosing full-expression.
因此,对于“为什么不将其传递到寄存器中”这个问题的简单回答是“因为它不能”。
现在,一个有趣的问题可能是“为什么 C++ Itanium ABI 决定采用它”。
虽然我不会声称我对基本原理有深入的了解,但我想到了两件事:
关于c++ - 与普通指针相比,按值传递 `unique_ptr` 是否会降低性能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54225864/
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use
我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些
如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只
如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:
我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我
这是我的网络应用:classFront我是这样开始的(请不要建议使用Rack):Front.start!这是我的Puma配置对象,我不知道如何传递给它:require'puma/configuration'Puma::Configuration.new({log_requests:true,debug:true})说真的,怎么样? 最佳答案 配置与您运行的方式紧密相关puma服务器。运行的标准方式puma-pumaCLI命令。为了配置puma配置文件config/puma.rb或config/puma/.rb应该提供(参见examp
我有一个电子邮件表格。但是我正在制作一个测试电子邮件表单,用户可以在其中添加一个唯一的电子邮件,并让电子邮件测试将其发送到该特定电子邮件。为了简单起见,我决定让测试电子邮件通过ajax执行,并将整个内容粘贴到另一个电子邮件表单中。我不知道如何将变量从我的HAML发送到我的Controllernew.html.haml-form_tagadmin_email_blast_pathdoSubject%br=text_field_tag'subject',:class=>"mass_email_subject"%brBody%br=text_area_tag'message','',:nam
我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“
我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0