运算符重载对于类和基元的行为不同 [英] Operator Overloading behaves differently for classes and primtives

查看:77
本文介绍了运算符重载对于类和基元的行为不同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码在使用 g++ 编译和运行时输出 22.

#include int main(){int a = 5;int c = ++a + ++a + ++a;std::cout <<c<<std::endl;返回0;}

浮点数也计算为相同的值.

而以下整数包装类输出 24

#include 类 In{上市:整数数据;整数(整数值):数据(值){}国际与运算符++(){++数据;返回 *this;}整数运算符+( const Int& b ){返回 Int( data + b.data );}};int main(){整数 a = 5;整数 c = ++a + ++a + ++a;std::cout <<c.数据<

我无法理解为什么输出会有差异.

  • 我首先想到的是求值顺序,但对于整数和类不应该是一样的.
  • 我还认为我的实现是否有误,但大多数文本还提到了前缀增量运算符的相同实现.

有人能详细解释一下这里发生了什么吗?

除此之外,当使用 clang 编译两个代码时,第一个代码输出 21,而第二个代码输出 22.

PS:我知道我不应该使用这样的表达式,但我的问题是为什么类的行为与原始类型不同.他们不应该都解析为相同的语法树并以相同的顺序进行评估.即使行为未定义但对于同一个编译器,它们的行为不应该以类似的方式

解决方案

Both int c = ++a + ++a + ++a;Int c = ++a+ ++a + ++a; 导致未定义的行为.
你应该避免这样编码.

参见 https://en.cppreference.com/w/cpp/语言/operator_incdec#Example,

并查看未定义行为部分 cppreference.com 的评估顺序页面:

<块引用>

未定义的行为

  1. 如果一个标量对象的副作用相对于同一个标量对象的另一个副作用是无序的,则行为是未定义的.

    i = ++i + 2;//在 C++11 之前未定义的行为i = i++ + 2;//在 C++17 之前未定义的行为f(i = -2, i = -2);//在 C++17 之前未定义的行为f(++i, ++i);//在 C++17 之前未定义的行为,在 C++17 之后未指定i = ++i + i++;//未定义的行为

  2. 如果相对于使用同一标量对象的值进行的值计算,标量对象的副作用是未排序的,则行为未定义.

    cout <<<我<<我++;//在 C++17 之前未定义的行为a[i] = i++;//在 C++17 之前未定义的行为n = ++i + i;//未定义的行为

在这里你可以用不同的编译器运行你的代码
Visual C++ 上的评估顺序
Zapcc 和 GCC 上的评估顺序

剧透:Visual C++ 对原始类型和类的行为方式相同

在 rextester 上,您也可以尝试 Clang 和 GCC,但我无法在其他链接下面添加这些链接,除非编辑器告诉我有一些非格式化代码(没有)
Clang 上的评估顺序
GCC 上的评估顺序

The following code when compiled and run using g++ outputs 22.

#include <iostream>

int main(){
    int a = 5;
    int c = ++a + ++a + ++a;
    std::cout << c << std::endl;
    return 0;
}

Floats also evaluate to the same value.

Whereas the following integer wrapper class outputs 24

#include <iostream>

class Int{
public:
    int data;
    
    Int( int value ) : data(value){}
    
    Int& operator++(){
       ++data;
       return *this;
    }
    
    Int operator+( const Int& b ){
        return Int( data + b.data );
    }
    
};

int main(){
    Int a = 5;
    Int c = ++a + ++a + ++a;
    std::cout << c.data << std::endl;
    return 0;
}

I am unable to understand why is there a difference in the outputs.

  • The first thing that came to my mind was the order of evaluation but shouldn't it be same for ints as well a classes.
  • I also thought if my implementation was wrong but most text also mentions the same implementation for prefix increment operator.

Could someone explain me in detail whats going on here?

Apart from this when both codes are compiled using clang the first code outputs 21 while the second code outputs 22.

PS : I know i shouldn't be using such an expression but my question is why are classes behaving differently than primitive types. Shouldn't they both parse to the same syntax tree and get evaluated in the same order. Even though the behaviour is undefined but for the same compiler, shouldn't they both behave in a similar manner

解决方案

Both int c = ++a + ++a + ++a; and Int c = ++a + ++a + ++a; result in undefined behavior.
You should avoid coding like that.

See https://en.cppreference.com/w/cpp/language/operator_incdec#Example,

and see the Undefined behaviour section of cppreference.com's Order of evaluation page:

Undefined behavior

  1. If a side effect on a scalar object is unsequenced relative to another side effect on the same scalar object, the behavior is undefined.

    i = ++i + 2;       // undefined behavior until C++11
    i = i++ + 2;       // undefined behavior until C++17
    f(i = -2, i = -2); // undefined behavior until C++17
    f(++i, ++i);       // undefined behavior until C++17, unspecified after C++17
    i = ++i + i++;     // undefined behavior
    

  2. If a side effect on a scalar object is unsequenced relative to a value computation using the value of the same scalar object, the behavior is undefined.

    cout << i << i++; // undefined behavior until C++17
    a[i] = i++;       // undefined behavior until C++17
    n = ++i + i;      // undefined behavior
    

Here you can run your code with different compilers
Evaluation order on Visual C++
Evaluation order on Zapcc and GCC

Spoiler: Visual C++ behaves in the same way for primitive types and classes

On rextester you can try also Clang and GCC, but I can't add these links below the others without the editor telling me that there is some non-formatted code (which there isn't)
Evaluation order on Clang
Evaluation order on GCC

这篇关于运算符重载对于类和基元的行为不同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆