无法解释编译器的行为

时间:2016-05-15 20:18:26

标签: c++ destructor operator-keyword

考虑这个简单的代码:

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;
}

输出:

  增量前

:1   摧毁2
  增量后:2
  摧毁2

为什么a的值在被销毁之前更多?

3 个答案:

答案 0 :(得分:4)

在operator ++方法中,您创建临时A对象,然后在从函数返回时将其销毁。 还应该有另一个复制构造和销毁,但RVO除此之外。

当您将日志添加到构造函数时,您将看到更好的内容。我还允许自己将printf更改为cout,以获得更多c ++ ish编码风格。

#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
    }
};

答案 1 :(得分:2)

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; }

答案 2 :(得分:0)

非常简单:

a = ++a;

首先,创建一个新的临时A对象,其中包含value 2value + 1 = 2),此对象被移动/复制到a然后销毁(这是你看到的第一个destroying 2打印件)。现在编译器生成的移动/复制构造函数只对这些成员value进行了memcopy。分配给临时对象时,value2,因此a value也将2。因此,最后两个printf打印2并不奇怪。