无法解释编译器的行为
Can't explain compiler's behavior
考虑这个简单的代码:
class A {
public:
int value;
A(int value) { this->value = value; }
~A() { printf("destroying %d\n", value); }
A operator ++() { return A(value + 1); }
};
int main() {
A a(1);
printf("before increment: %d\n", a.value);
a = ++a;
printf("after increment: %d\n", a.value);
return 0;
}
这输出:
before increment: 1
destroying 2
after increment: 2
destroying 2
为什么a
销毁前的值多了1?
很简单:
a = ++a;
首先,创建一个新的临时A
对象,它持有value
的2
(value + 1 = 2
),这个对象是moved/copied到a
然后销毁(这是您看到的第一个 destroying 2
印刷品)。现在编译器生成的 move/copy 构造函数只是对成员进行 memcopy,在本例中为 value
。 value
在分配给临时对象时是 2
,因此 a
的 value
也将是 2
。因此,最后两个 printf
打印出 2
也就不足为奇了。
在 operator++ 方法中,您创建临时 A 对象,然后当您从函数 return 中销毁该对象。 应该还有一个复制构造和销毁,但是RVO省略了这个。
当您将日志添加到构造函数时,您也会更清楚地看到发生了什么。我还允许自己将 printf 更改为 cout,以获得更多 c++ 风格的编码风格。
#include <iostream>
class A {
public:
int value;
A(int value) {
std::cout << "creating " << value << std::endl;
this->value = value;
}
~A() {
std::cout << "destroying " << value << std::endl;
}
A operator ++() { return A(value + 1); }
};
int main() {
A a(1);
std::cout << "before increment: " << a.value << std::endl;
a = ++a;
std::cout << "after increment: " << a.value << std::endl;
return 0;
}
输出:
creating 1
before increment: 1
creating 2
destroying 2
after increment: 2
destroying 2
您还可以阅读有关运算符重载的规范实现:
http://en.cppreference.com/w/cpp/language/operators
operator++ 重载应如下所示:
struct X
{
X& operator++() // prefix version
{
// actual increment takes place here
return *this;
}
X operator++(int) // postfix version
{
X tmp(*this); // copy
operator++(); // pre-increment
return tmp; // return old value
}
};
int main() {
A a(1); // a.value = 1;
printf("before increment: %d\n", a.value);
a = ++a; // 1. create temporary object of type A with a.value+1
// 2. copy temporary object to object a.
// 3. destroy temporary object.
printf("after increment: %d\n", a.value);
return 0;
}
基本上,为了清楚起见,您可以在此处将预递增运算符声明为常量
A operator ++() const { return A(value + 1); }
但预期的行为是:
A& operator ++() { ++value; return *this; }
考虑这个简单的代码:
class A {
public:
int value;
A(int value) { this->value = value; }
~A() { printf("destroying %d\n", value); }
A operator ++() { return A(value + 1); }
};
int main() {
A a(1);
printf("before increment: %d\n", a.value);
a = ++a;
printf("after increment: %d\n", a.value);
return 0;
}
这输出:
before increment: 1
destroying 2
after increment: 2
destroying 2
为什么a
销毁前的值多了1?
很简单:
a = ++a;
首先,创建一个新的临时A
对象,它持有value
的2
(value + 1 = 2
),这个对象是moved/copied到a
然后销毁(这是您看到的第一个 destroying 2
印刷品)。现在编译器生成的 move/copy 构造函数只是对成员进行 memcopy,在本例中为 value
。 value
在分配给临时对象时是 2
,因此 a
的 value
也将是 2
。因此,最后两个 printf
打印出 2
也就不足为奇了。
在 operator++ 方法中,您创建临时 A 对象,然后当您从函数 return 中销毁该对象。 应该还有一个复制构造和销毁,但是RVO省略了这个。
当您将日志添加到构造函数时,您也会更清楚地看到发生了什么。我还允许自己将 printf 更改为 cout,以获得更多 c++ 风格的编码风格。
#include <iostream>
class A {
public:
int value;
A(int value) {
std::cout << "creating " << value << std::endl;
this->value = value;
}
~A() {
std::cout << "destroying " << value << std::endl;
}
A operator ++() { return A(value + 1); }
};
int main() {
A a(1);
std::cout << "before increment: " << a.value << std::endl;
a = ++a;
std::cout << "after increment: " << a.value << std::endl;
return 0;
}
输出:
creating 1
before increment: 1
creating 2
destroying 2
after increment: 2
destroying 2
您还可以阅读有关运算符重载的规范实现:
http://en.cppreference.com/w/cpp/language/operators
operator++ 重载应如下所示:
struct X
{
X& operator++() // prefix version
{
// actual increment takes place here
return *this;
}
X operator++(int) // postfix version
{
X tmp(*this); // copy
operator++(); // pre-increment
return tmp; // return old value
}
};
int main() {
A a(1); // a.value = 1;
printf("before increment: %d\n", a.value);
a = ++a; // 1. create temporary object of type A with a.value+1
// 2. copy temporary object to object a.
// 3. destroy temporary object.
printf("after increment: %d\n", a.value);
return 0;
}
基本上,为了清楚起见,您可以在此处将预递增运算符声明为常量
A operator ++() const { return A(value + 1); }
但预期的行为是:
A& operator ++() { ++value; return *this; }