草庐IT

c++ - 我现在应该按值(value)传递吗?

coder 2024-02-23 原文

在此talk (对声音感到抱歉)Chandler Carruth 建议在绝大多数情况下不要通过引用传递,甚至是 const 引用传递,因为它限制了后端执行优化的方式。

他声称在大多数情况下拷贝可以忽略不计 - 我很高兴相信,大多数数据结构/类等在堆栈上分配了非常小的部分 - 特别是与后端必须假设指针相比别名和所有可以对引用类型做的讨厌的事情。

假设我们在堆栈上有一个大对象 - 比如说 ~4kB 和一个对该对象的实例执行某些操作的函数(假设是独立函数)。

传统上我会写:

void DoSomething(ExpensiveType* inOut);
ExpensiveType data;
...
DoSomething(&data);

他建议:

ExpensiveType DoSomething(ExpensiveType in);
ExpensiveType data;
...
data = DoSomething(data);

根据我从谈话中得到的信息,第二个往往会优化得更好。不过,我制作这样的东西有多大限制,还是后端复制省略的东西几乎在所有情况下都会更喜欢这些值?

编辑:为了澄清我对整个系统感兴趣,因为我觉得这将是我编写代码方式的重大改变,我已经使用 refs over values drilled into anything than integral打字很长时间了。

EDIT2:我也测试过,结果和代码here .真的没有竞争,因为我们长期以来一直被教导,指针是一种更快的做事方法。现在让我感兴趣的是,为什么在那次谈话中有人建议我们转向按值(value)传递,但由于数字不支持它,所以我不会这样做。

最佳答案

我现在看了钱德勒演讲的部分内容。我认为围绕“我现在应该始终按值(value)传递”的一般性讨论并没有使他的谈话公正。编辑:实际上他的演讲之前已经讨论过,在这里 value semantics vs output params with large data structures在 Eric Niebler 的博客中,http://ericniebler.com/2013/10/13/out-parameters-vs-move-semantics/ .

回到钱德勒。在关键说明中,他特别(在其他地方提到的 4x-5x 分钟标记附近)提到了以下几点:

  • 如果优化器看不到被调用函数的代码,那么您遇到的问题比传递引用或值要大得多。它几乎阻止了优化。 (此时有一个关于链接时间优化的后续问题,可能稍后会讨论,我不知道。)
  • 他推荐使用移动语义的“新古典”返回值方式。与将对现有对象的引用作为输入输出参数传递的旧学校方法不同,值应该在本地构造并移出。最大的优势是优化器可以确保对象的任何部分都没有别名,因为只有函数可以访问它。
  • 他提到了线程、将变量的值存储在全局变量中,以及输出等可观察行为作为未知数的示例,这些未知数在仅传递引用/指针时会阻止优化。我认为一个抽象的描述可能是“本地代码不能假设在其他地方未检测到本地值更改,也不能假设本地未更改的值根本没有更改”。对于本地拷贝,可以做出这些假设。

显然,当按值传递时(如果对象不能移动,返回时可能),复制成本和优化 yield 之间存在权衡。大小和其他使复制成本高昂的因素将使平衡向引用策略倾斜,而函数中对对象的大量可优化工作则使它向值(value)传递倾斜。 (他的示例涉及指向 int 的指针,而不是指向 4k 大小对象的指针。)

根据我看过的部分,我不认为钱德勒提倡按值(value)传递作为一种放之四海而皆准的策略。我认为他主要是在传递 out 参数而不是返回新对象的上下文中反对通过引用传递。他的示例与修改现有对象的函数无关。

一般说明:

程序应该表达程序员的意图。如果您需要拷贝,请务必复制!如果要修改现有对象,请务必使用引用或指针。仅当副作用或运行时行为变得难以忍受时;真的只有这样才能尝试做一些聪明的事情。

还应注意,编译器优化有时会令人惊讶。其他平台、编译器、编译选项、类库甚至您自己的代码中的小改动都可能会阻止编译器进行救援。在许多情况下,更改的运行时成本是完全出乎意料的。

关于c++ - 我现在应该按值(value)传递吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32845136/

有关c++ - 我现在应该按值(value)传递吗?的更多相关文章

  1. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  2. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  3. ruby - 按值降序排列散列,然后按升序键入 ruby - 2

    我有这样的哈希trial_hash={"key1"=>1000,"key2"=>34,"key3"=>500,"key4"=>500,"key5"=>500,"key6"=>500}我按值降序排列:my_hash=trial_hash.sort_by{|k,v|v}.reverse我现在是这样理解的:[["key1",1000],["key4",500],["key5",500],["key6",500],["key3",500],["key2",34]]但我希望当值相同时按键的升序排序。我该怎么做?例如:上面的散列将以这种方式排序:[["key1",1000],["key3",500

  4. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的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

  5. ruby-on-rails - 我更新了 ruby​​ gems,现在到处都收到解析树错误和弃用警告! - 2

    简而言之错误:NOTE:Gem::SourceIndex#add_specisdeprecated,useSpecification.add_spec.Itwillberemovedonorafter2011-11-01.Gem::SourceIndex#add_speccalledfrom/opt/local/lib/ruby/site_ruby/1.8/rubygems/source_index.rb:91./opt/local/lib/ruby/gems/1.8/gems/rails-2.3.8/lib/rails/gem_dependency.rb:275:in`==':und

  6. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用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”以实现该目的?如果我想通过传递一些

  7. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  8. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在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中能不能做到类似的简洁?我可以只

  9. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将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.你能做的最好的事情是:

  10. ruby-on-rails - Rails 单表继承 : How to override the value written to the type field - 2

    在我的系统中,我已经定义了STI。Dog继承自Animal,在animals表中有一个type列,其值为"Dog"。现在我想让SpecialDog继承自dog,只是为了在某些特殊情况下稍微修改一下行为。数据还是一样。我需要通过SpecialDog运行的所有查询,以返回数据库中类型为Dog的值。我的问题是因为我有一个type列,rails将WHERE"animals"."type"IN('SpecialDog')附加到我的查询中,所以我不能获取原始的Dog条目。所以我想要的是以某种方式覆盖rails在通过SpecialDog访问数据库时使用的值,使其表现得像Dog。有没有办法覆盖用于类型

随机推荐