类 和基元的运算符重载行为不同
Operator Overloading behaves differently for classes and primtives
以下代码在编译时 运行 使用 g++ 输出 22
。
#include <iostream>
int main(){
int a = 5;
int c = ++a + ++a + ++a;
std::cout << c << std::endl;
return 0;
}
浮点数也计算为相同的值。
而下面的整数包装器 class 输出 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;
}
我无法理解为什么输出会有所不同。
- 我首先想到的是求值顺序,但整数和 classes 不应该相同吗?
- 我也想过我的实现是否有误,但大多数文本也提到了前缀增量运算符的相同实现。
有人可以详细解释一下这是怎么回事吗?
除此之外,当使用 clang
编译两个代码时,第一个代码输出 21
而第二个代码输出 22
.
PS :我知道我不应该使用这样的表达式,但我的问题是为什么 classes 的行为与原始类型不同。他们不应该都解析为相同的语法树并以相同的顺序进行评估吗?即使行为未定义但是对于同一个编译器,它们不应该以相似的方式表现吗
int c = ++a + ++a + ++a;
和 Int c = ++a + ++a + ++a;
都会导致未定义的行为。
你应该避免这样编码。
参见https://en.cppreference.com/w/cpp/language/operator_incdec#Example、
并查看 cppreference.com 的 评估顺序 页面的 Undefined behaviour section:
Undefined behavior
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
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
在这里你可以运行你的代码与不同的编译器
Evaluation order on Visual C++
Evaluation order on Zapcc and GCC
剧透:Visual C++ 对基本类型和 类
的行为方式相同
在 rextester 上,您也可以尝试 Clang 和 GCC,但是我无法在其他链接下方添加这些链接,除非编辑告诉我有一些未格式化的代码(没有)
Evaluation order on Clang
Evaluation order on GCC
以下代码在编译时 运行 使用 g++ 输出 22
。
#include <iostream>
int main(){
int a = 5;
int c = ++a + ++a + ++a;
std::cout << c << std::endl;
return 0;
}
浮点数也计算为相同的值。
而下面的整数包装器 class 输出 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;
}
我无法理解为什么输出会有所不同。
- 我首先想到的是求值顺序,但整数和 classes 不应该相同吗?
- 我也想过我的实现是否有误,但大多数文本也提到了前缀增量运算符的相同实现。
有人可以详细解释一下这是怎么回事吗?
除此之外,当使用 clang
编译两个代码时,第一个代码输出 21
而第二个代码输出 22
.
PS :我知道我不应该使用这样的表达式,但我的问题是为什么 classes 的行为与原始类型不同。他们不应该都解析为相同的语法树并以相同的顺序进行评估吗?即使行为未定义但是对于同一个编译器,它们不应该以相似的方式表现吗
int c = ++a + ++a + ++a;
和 Int c = ++a + ++a + ++a;
都会导致未定义的行为。
你应该避免这样编码。
参见https://en.cppreference.com/w/cpp/language/operator_incdec#Example、
并查看 cppreference.com 的 评估顺序 页面的 Undefined behaviour section:
Undefined behavior
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
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
在这里你可以运行你的代码与不同的编译器
Evaluation order on Visual C++
Evaluation order on Zapcc and GCC
剧透:Visual C++ 对基本类型和 类
的行为方式相同在 rextester 上,您也可以尝试 Clang 和 GCC,但是我无法在其他链接下方添加这些链接,除非编辑告诉我有一些未格式化的代码(没有)
Evaluation order on Clang
Evaluation order on GCC