C++ 的目标之一是允许用户定义类型的行为与内置类型一样好。这似乎失败的一个地方是编译器优化。如果我们假设 const 非 volatile 成员函数在道德上等同于读取(对于用户定义的类型),那么为什么不允许编译器消除对此类函数的重复调用呢?例如
class C {
...
public:
int get() const;
}
int main() {
C c;
int x{c.get()};
x = c.get(); // why not allow the compiler to eliminate this call
}
允许这样做的论点与复制省略的论点相同:虽然它改变了操作语义,但它应该适用于遵循良好语义实践的代码,并在效率/模块化方面提供实质性改进。 (在这个例子中,它显然很愚蠢,但它变得非常有值(value),比如说,在函数被内联时消除冗余的迭代安全检查。)
当然,对于返回非 const 引用的函数,只允许返回值或 const 引用的函数允许这样做是没有意义的。
我的问题是是否有一个基本的技术论点反对这一点并不同样适用于复制省略。
注意:为了清楚起见,我并不是建议编译器查看 get() 的定义内部。我是说 get() 本身的声明应该允许编译器省略额外的调用。我并不是说它保留了假设规则;我声称,就像在复制省略中一样,这是我们希望允许编译器违反假设规则的情况。如果您在编写代码时希望副作用在语义上可见,并且不希望消除冗余调用,则不应将您的方法声明为 const。
最佳答案
基于对问题的澄清的新答案
C::get 需要比 const 更强的注解。就目前而言,const 是一种 promise ,即该方法不会(概念上)修改对象。它不保证与全局状态或副作用的交互。
因此,如果新版本的 C++ 标准为 as-if 规则开辟了另一个异常(exception),就像它对复制省略所做的那样,仅基于一个方法被标记为 const 的事实,它将破坏许多现有代码.标准委员会似乎非常努力地尝试不破坏现有代码。
(复制省略也可能破坏了一些代码,但我认为与您提议的相比,这实际上是一个非常小的异常(exception)。)
您可能会争辩说我们应该重新指定 const 在方法声明中的含义,赋予它更强的含义。这将意味着您不能再拥有常量的 C::print 方法,因此这种方法似乎也会破坏许多现有代码。
所以我们必须发明一个新的注释,比如 pure_function。要将其纳入标准,您必须提出它并可能说服至少一个编译器制造商将其作为扩展来实现,以说明它的可行性和有用性。
我怀疑增量实用程序非常低。如果您的 C::get 是微不足道的(没有与全局状态的交互并且没有可观察到的副作用),那么您最好在类定义中定义它,从而使其可用于内联。我相信内联将允许编译器生成与声明中的 pure_function 标记一样最佳的代码(甚至可能更多),因此我不希望 pure_function 标记的增量好处足以说服标准委员会,编译器制造商和语言用户采用它。
原始答案
C::get 可能依赖于全局状态并且它可能具有可观察到的副作用,其中任何一个都会导致忽略第二次调用的错误。这将违反假设规则。
问题是编译器在调用站点进行优化时是否知道这一点。在编写示例时,只有 C::get 的声明在范围内。定义在别处,大概在另一个编译单元中。因此,编译器在编译和优化调用代码时必须假设最坏的情况。
现在,如果 C::get 的定义既微不足道又在 View 中,那么我想编译器理论上有可能实现没有副作用或非确定性行为,但我怀疑大多数优化器会变得如此激进。除非 C::get 是内联的,否则我想分析的路径会呈指数级增长。
如果您想跳过整个赋值语句(而不是仅仅第二次调用 C::get),那么编译器还必须检查赋值运算符的副作用,并且依赖全局状态以确保优化不会违反假设规则。
关于c++ - 为什么不允许在 const 非 volatile 成员函数上消除公共(public)子表达式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23722601/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
为什么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
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从