运算符<< :std :: cout<< i<< (i< 1);

时间:2010-04-21 21:13:28

标签: c++

我使用流运算符<<和位移算子<<<在一条线上。 我有点困惑,为什么代码A)不会产生与代码B相同的输出?

A)

int i = 4;  
std::cout << i << " " << (i << 1) << std::endl;   //4 8

B)

myint m = 4;
std::cout << m << " " << (m << 1) << std::endl;   //8 8

类myint:

class myint {
    int i;
public:
    myint(int ii) {
        i = ii;
    }
    inline myint operator <<(int n){
        i = i << n;
        return *this;
    }
    inline operator int(){
        return i;
    }
};
提前谢谢你 哎呀

7 个答案:

答案 0 :(得分:8)

你的第二个例子是未定义的行为。

您已在<<课程中定义了myint运算符,就好像它实际上是<<=一样。执行i << 1时,i中的值不会被修改,但是当您执行m << 1时,m 中的值会被修改。< / p>

在C ++中,对于没有插入序列点的变量进行读取和写入(或多次写入)是未定义的行为,对于它们的参数,函数调用和运算符不是。代码

是不确定的
std::cout << m << " " << (m << 1) << std::endl;  

将在m更新m之前或之后输出第一个m << 1。实际上,您的代码可能会做一些完全奇怪或崩溃的事情。未定义的行为可以导致任何事情,所以避免它。

<<定义myint运算符的正确方法之一是:

myint operator<< (int n) const
{
   return myint(this->i << n);
}

this->并非严格必要,只是我在重载运算符时的风格)

答案 1 :(得分:5)

因为int&lt;&lt; X返回一个新的int。 myint&lt;&lt; X修改当前的myint。你的myint&lt;&lt;操作员应该固定做前者。

你第一次获得8的原因是显然m&lt;&lt;在您的实现中首先调用1。实现可以按任何顺序自由执行。

答案 2 :(得分:2)

你的&lt;&lt;运算符实际上是&lt;&lt;&lt; =运算符。如果用

替换该行
std::cout << i << " " << (i <<= 1) << std::endl;   //8 8

你应该得到8 8。

答案 3 :(得分:2)

由于mmyInt,您的第二个示例可以重写为:

std::cout << m << " " << (m.operator<<( 1)) << std::endl; 

子表达式m(m.operator<<( 1))的评估顺序是未指定的,所以没有说明m您将获得{{1}的第1个表达式用于(这是一个简单的m表达式)。所以你可能得到“4 8”的结果,或者你可能得到“8 8”。

请注意,语句不会导致未定义的行为,因为在修改m和“读取”之间存在序列点(至少一个函数调用)。但是子表达式的评估顺序是未指定的,因此虽然编译器必须产生结果(它不能崩溃 - 至少不合法),但是不应该说它应该产生哪两个可能的结果。

因此该语句与具有未定义行为的语句一样有用,也就是说它不是非常有用。

答案 4 :(得分:1)

井(m&lt;&lt; 1)在m之前被评估,因此m已经保持8,如在你的运营商&lt;&lt;你覆盖自己的价值。

这是你身边的错误行为,操作员&lt;&lt;应该是const而不是改变你的对象。

答案 5 :(得分:0)

因为myint的<<运算符修改了它的lhs。因此,在评估m << 1之后,m实际上将具有值8(而i << 1仅返回8,但不使i等于8)。由于未指定m<<1是否在cout << m之前执行(因为未指定函数或运算符的参数的评估顺序),因此未指定输出是否为{{1} }或8 8

答案 6 :(得分:0)

C ++语言没有定义运算符的评估顺序。它只定义了它们的相关性。

由于结果取决于在表达式中评估operator<<函数的时间,因此结果未定义。

代数operator $函数应始终为const并返回一个新对象:

inline myint operator <<(int n) const { // ensure that "this" doesn't change
    return i << n; // implicit conversion: call myint::myint(int)
}