【问题标题】:C++: Using '.' operator on expressions and function callsC++:使用“。”表达式和函数调用的运算符
【发布时间】:2011-02-21 19:05:10
【问题描述】:

我想知道像这样使用成员运算符. 是否是一种好习惯:

someVector = (segment.getFirst() - segment.getSecond()).normalize().normalCCW();

只是为了展示我想知道的两个不同的事情,即使用(expressions).member/function()foo.getBar().getmoreBar() 是否符合可读性和可维护性的精神。在我学习的所有 c++ 代码和书籍中,我从未见过它以这种方式使用过,但它本身却非常容易使用。不过不想养成任何坏习惯。

可能比这更重要(或更不重要),我还想知道以这种方式使用它是否会有任何性能增益/损失,或者会导致程序错误的不可预见的陷阱。

提前谢谢你!

【问题讨论】:

  • var 本身就是一个表达式。 var.member 更是如此。所以按照这个逻辑...
  • 查看此相关主题:Is this code well-defined?

标签: c++ performance coding-style operator-keyword class-members


【解决方案1】:

或无法预料的陷阱,会在程序中引入错误

嗯,可能的陷阱是

  1. 更难调试。您将无法查看每个函数调用的结果,因此如果其中一个返回了意外的内容,您需要将其分成更小的部分以查看发生了什么。此外,链中的任何调用都可能完全失败,因此,您可能需要再次分解它以找出哪个调用失败。

  2. 更难阅读(有时)。链接函数调用会使代码更难阅读。这取决于情况,这里没有硬性规定。如果表达式甚至有些复杂,它可能会使事情难以理解。阅读您的具体示例我没有任何问题。

这最终归结为个人喜好。我并没有努力尽可能多地放在一条线上,而且我已经被咬了足够多的时间了,因为我把不应该的地方用链子串起来,我倾向于把事情弄散一点。但是,对于不太可能失败的简单表达式,链接就可以了。

【讨论】:

  • 谢谢!我将不得不避免将它与比示例更复杂的东西一起使用。我有时会忘记很多函数在失败时会返回垃圾,尤其是那些返回指针的函数。幸运的是,如果我告诉它,我的调试器会在语句中输入任何函数调用,这样至少不会很麻烦。
【解决方案2】:

是的,这是完全可以接受的,事实上,如果您不这样做,在很多情况下都会完全不可读。

这叫做方法链。

由于您没有创建临时变量,因此可能会获得一些性能提升。但无论如何,任何有能力的编译器都会对其进行优化。

【讨论】:

  • 顺便说一句,它还可以使代码在很多上下文中完全不可读。并且有可能(取决于它是如何实现的)引入一些范围错误。像大多数事情一样,它真的取决于你如何使用它:如果它使它更具可读性,那就去吧;如果它降低了可读性,请不要。
  • 我想知道这是否有名字!而且我很享受不必依赖临时变量而只是为了打破声明。 (尽管我仍然使用它们来缓存结果)@Zac:从大多数答案来看,这似乎是共识。我有时会忘记编码涉及这样的判断调用。我必须确保只考虑你从现在开始所说的最后一句话,谢谢!
【解决方案3】:

按照您展示的方式使用它是完全有效的。例如在 C++ faq lite 中描述的named parameter idiom 中使用。

不总是使用它的一个原因是当您出于性能原因(如果规范化的成本很高并且您必须多次使用它,最好将结果存储在变量中)或可读性而必须存储中间结果时.

my2c

【讨论】:

  • 我刚刚读完你链接的那篇文章。这为我的一些问题课程提供了很多想法。谢谢!
  • @Clairvoire:不客气。当您已经掌握了 C++ 基本技能时,必须阅读 C++ faq lite。祝你的代码好运:)
【解决方案4】:

使用变量来保存中间结果有时可以提高可读性,尤其是在使用好的变量名时。过多的链接会让人很难理解正在发生的事情。您必须根据自己的判断来决定是否值得使用变量来分解链。你上面举的例子对我来说并不过分。如果启用优化,性能应该不会有太大差异。

【讨论】:

  • 谢谢!奇怪的是,我发现几乎 50% 的时间都是在编码时,花在为变量/类/函数想好名字上。但是,在涉及临时变量时总是会失败,最终放弃并称其为“double temp_double”或同样懒惰的东西。我会尽量避免使用过多的链条
  • 词库或其他库有时可以为您提供好的变量名称的灵感。如果您花时间提出简洁、不言自明的名称,那么您将在以后编写代码时节省时间。代码已经不言自明了。
【解决方案5】:
someVector = (segment.getFirst() - segment.getSecond()).normalize().normalCCW();

不是你的问题的答案,但我应该告诉你 根据 C++ 标准,表达式 (segment.getFirst() - segment.getSecond()) 的行为没有明确定义。标准未指定每个操作数的评估顺序!

另外,请参阅此相关主题:Is this code well-defined?

【讨论】:

  • 哎呀,我想我们可以假设 getFirst() 和 getSecond() 都返回一个 Vector,它已经 - 重载,例如,为了
  • @Clairvoire:这是有道理的。我的帖子应该以防万一。毕竟,我不是想回答!
  • 好的!并感谢该链接。我很高兴用这种方法链接的东西做的任何事情都不会出现在我的脑海中。
  • 什么没有明确定义?假设 getFirst() 和 getSecond() 是 const 函数(我认为这是一个安全的假设),结果是完美定义的。如果您指的是调用两个函数的顺序,那么您是正确的,但我认为这与计算无关。
【解决方案6】:

我想你正在做的事情可读性较差,但是另一方面,太多的临时变量也可能变得不可读。

就性能而言,我确信在制作临时变量时会有一点开销,但编译器可以对其进行优化。

【讨论】:

    【解决方案7】:

    以这种方式使用它没有什么大问题 - 一些 API 从方法链中受益匪浅。另外,创建一个变量然后只使用一次是一种误导。当有人阅读下一行时,他们不必考虑您现在没有保留的所有变量。

    【讨论】:

    • 其实,既然你提到了。我将不得不重新检查我是如何使用我拥有的一些库的,看看这是否会更好地与它们一起使用。谢谢!
    【解决方案8】:

    这取决于你在做什么。

    为了便于阅读,您应该尝试使用中间变量。
    将计算结果分配给指针,然后使用它们。

    【讨论】:

    • 这就是我学到的主要方法。但我不确定我是否遵循指针所需要的...
    • 您想保存结果...因此,如果您不使用指针,而是使用类变量,它将调用复制构造函数并复制数据。浪费时间。
    • 你能举个例子来说明你的建议吗?如果函数不返回指针,如何将计算结果赋值给指针?
    猜你喜欢
    • 2023-03-07
    • 1970-01-01
    • 2011-02-23
    • 2020-02-08
    • 1970-01-01
    • 2016-11-05
    • 2012-11-29
    • 2016-12-05
    • 2015-05-08
    相关资源
    最近更新 更多