【问题标题】:why comma,address-of, logical AND and logical OR operators should not be overloaded in c++?为什么逗号、地址、逻辑 AND 和逻辑 OR 运算符不应在 C++ 中重载?
【发布时间】:2015-12-15 06:33:16
【问题描述】:

有人可以举例说明为什么在 c++ 中重载逗号、地址、逻辑 AND 和逻辑 OR 运算符不是一个好习惯吗?

【问题讨论】:

  • 如果你重载了逗号操作符,你就是 STL 改变他的 C++ STL 实现以在适当的地方做a, void(), b 的原因。
  • 我认为这个问题不应该作为“主要基于意见”而结束
  • 这句话是谁说的,什么时候说的?

标签: c++ oop c++11 operator-overloading logical-operators


【解决方案1】:

根本原因是这些运算符的重载版本与内置版本的行为不同。这可能会导致(人类)读/写代码的严重混乱。

  1. 逻辑运算符&&|| 内置版本表现出短路 优化:在a && b 等表达式中,评估a首先且仅当trueb 也被评估;同样,在a || b 中,a 首先被评估,并且只有在falseb 也被评估时。重载运算符 &&|| 没有短路优化(ab 总是被计算)并且参数的计算顺序也没有指定。

  2. 逗号运算符 内置版本保证参数按照它们出现的顺序进行计算,即在a,b 中,a 首先被计算,然后b。使用重载的逗号运算符,这种保证就失去了(取而代之的是函数参数机制发挥作用)。

  3. 地址操作符 内置地址操作符& 和重载的操作符在应用于不完整类型的对象时可能会产生混淆。考虑这段代码

    struct type;            // forward declaration: type is (as of yet) incomplete
    
    #include <memory>
    void foo(type &obj)     // allowed: take object of incomplete type by reference
    {
      auto ptr1 = &obj;                  // address of obj -- or not?
      auto ptr2 = std::addressof(obj);   // always address of obj    
    }
    
    // possibly in a different translation unit:
    struct type
    {
      type* operator&() { return nullptr; }
    };
    

    此代码显示unspecified behaviour:编译器可以在foo() 中实现&amp; 运算符的任一版本,但编写foo() 代码的人无法知道这一点或将使用哪个运算符。 这个问题在使用std::addressofptr2 时可以避免,即使type 有一个重载的&amp; 运算符,它也会获得与内置地址操作符的等价物。

【讨论】:

  • operator&amp; 的情况现在未指定,根据 CWG1458
【解决方案2】:

如果有人阅读代码并看到if(a &amp;&amp; b),他/她会怎么想?
如果 a 和 b 是像 boolint 这样的原生类型,那么每个人都知道它是如何工作的。

如果它们是类对象,大多数人会期望类在应用&amp;&amp; 之前提供operator bool() 或类似的查询它应该是什么布尔值。没有人会认为if(a.myMethod(b)) 是一种“花哨”的写法,也没有人会检查类定义 => 每个人都会误解和/或混淆条件的用途。
tldr,不要使用内置的 &amp;&amp; 作为不相关方法调用的缩写。

同样适用于||,

至于地址操作符,除了阅读混乱之外,在写代码的时候也很常见:指针地址通常可以为任何类型的任何变量获取,在做之前没有人会检查你的类定义。

除了可读性等,如果和以什么顺序评估参数不同:

对于if(a&amp;&amp;b) 通常来说,如果a 是false,那么b 甚至不再被检查,因为整个条件只能是假的。如果你有类似的东西。 if(a &amp;&amp; func1()) func2(); 其中func2() 的返回值很重要,func1() 仅在atrue 时执行,并且只有当两者都为真时才执行func2()。对于重载的&amp;&amp;func1()总是被执行。根据它的作用,这可能不是您想要的。

|| 类似:如果第一个参数是true,则通常不再查看第二个参数,因为无论如何整个条件都为真。对于重载,始终评估参数。

普通的逗号运算符a,b 保证ab 之前被评估/执行;重载时,它可以按任何顺序排列。

【讨论】:

  • 代码可读性是个问题。但是如果你查看这个链接securecoding.cert.org/confluence/display/cplusplus/…,这里解释的原因我很难理解。所以,我问了现在被否决的问题。
  • @bornfree 我说的不仅仅是可读性。 ...关于您的链接,我将添加...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-18
  • 2023-01-31
  • 2023-03-12
  • 1970-01-01
相关资源
最近更新 更多