Possible Duplicate:
Undefined Behavior and Sequence Points
重载后缀运算符时,我无法理解操作顺序。让我们来看看下面的两个小例子:
int i = 0;
std::cout << std::endl << "i: " << i;
i = ++i;
std::cout << std::endl << "i: " << i;
i = i++;
std::cout << std::endl << "i: " << i;
MyClass myObject;
std::cout << std::endl << "myObject: " << myObject.getMyValue();
myObject = ++myObject;
std::cout << std::endl << "myObject: " << myObject.getMyValue();
myObject = myObject++;
std::cout << std::endl << "myObject: " << myObject.getMyValue();
出现了两种截然不同的行为。输出结果如下:
i: 0
i: 1
i: 2
myObject: 0
myObject: 1
myObject: 1
不同的行为,你看。这是我的重载运算符方法的概要。
MyClass & MyClass::operator++ ()
{
++myValue;
return *this;
}
MyClass MyClass::operator++ (int postfixFlag)
{
MyClass myTemp(*this);
++myValue;
return myTemp;
}
好的。前缀是有道理的。你递增任何你需要的,然后返回相同的对象,现在修改,以防赋值。但是后缀让我感到困惑。它应该分配,然后递增。这里我们 self 分配。所以对于内置的整数类型,它是有意义的。我将 i
的值赋给它自己,然后 i
递增。很公平。但是假设 MyClass
是对 int 的重新创建。它从 0 开始,前缀递增,然后变为 1。然后是关键行。 我的对象 = 我的对象++
。这与 myObject = myObject.operator++(int postfixFlag)
相同。它被调用。 myTemp
初始化为值 1。它递增到 2。然后我们返回温度。如果我们正在分配给另一个对象,那就行得通了。但是这里我是自赋值的,所以在递增到 2 之后,myObject
被设置为等于返回的用初始值初始化的临时对象,我们又回到了 1!这就说得通了。但这是一种根本不同的行为。
我该如何解决? int 是怎么做到的?这个方法一般是怎么写的?您对与此相关的 C++ 行为和设计有何评论?等等。我现在有点困惑,因为书籍和在线示例似乎总是使用上述方法的变体。
感谢阅读,我们将不胜感激!
正如其他人所说,int 的行为是不确定的。但我想我会尝试解释为什么你的 MyClass 它永远不会达到 2。
诀窍在于您在后缀版本中执行以下三个步骤:
- 制作一个名为
myTemp
的 this
拷贝(myValue == 1
)。
- 递增
this->myValue
(所以 myTemp.myValue == 1
;this->myValue == 2
)。
- 返回
myTemp
(myValue == 1
)。
因此您正在修改 this
,但是调用 myObject++
的代码永远不会再看到 this
。它只会查看返回的值,它是 old myObject
的拷贝。
operator++ 的代码很好。问题在于您如何使用它——您不应该将预增量或后增量的结果写回同一个变量(行为未定义)。下面是一些可能更有指导意义的代码:
int i = 0;
std::cout << "i: " << i << std::endl;
int j = ++i;
std::cout << "i: " << i << ", j: " << j << std::endl;
int k = i++;
std::cout << "i: " << i << ", k: " << k << std::endl;
MyClass myObject;
std::cout << "myObject: " << myObject.getMyValue() << std::endl;
MyClass myObject1 = ++myObject;
std::cout << "myObject: " << myObject.getMyValue()
<< ", myObject1: " << myObject1.getMyValue() << std::endl;
MyClass myObject2 = myObject++;
std::cout << "myObject: " << myObject.getMyValue()
<< ", myObject2: " << myObject2.getMyValue() << std::endl;
这打印:
i: 0
i: 1, j: 1
i: 2, k: 1
myObject: 0
myObject: 1, myObject1: 1
myObject: 2, myObject2: 1
我更改了您的代码,这样它就不会重新分配给自己,而是每次都分配给一个新变量。请注意,在 int
和 MyClass
两种情况下,主变量 (i
/myObject
) 都会递增次。但是,在预增量情况下,新变量 (j
/myObject1
) 具有新值,而在后增量情况下,新变量 (k
/myObject2
) 采用旧值。
编辑:只是回答问题的另一部分,“int 是如何做到的?”我假设这个问题的意思是“int
类中的预增量和后增量代码是什么样的,我怎样才能使我的相同?”答案是,没有“int
类”。 int
是 C++ 中的一种特殊内置类型,编译器对其进行特殊处理。这些类型不是用普通的 C++ 代码定义的,它们是硬编码到编译器中的。
注意:对于任何想自己尝试的人,这里是问题未包含的 MyClass
的代码:
class MyClass
{
private:
int myValue;
public:
MyClass() : myValue(0) {}
int getMyValue() { return myValue; }
MyClass& operator++();
MyClass operator++(int postfixFlag);
};