简体   繁体   中英

C++ Destructor runs twice

See the program below. The program should print 1 as 1 counter object still exists, but when compiled with GCC, it prints 0. Why is that? Is this a compiler bug? This only occurs when returning from a different scope. Removing the if completely fixes it on all compilers.

#include <iostream>

int counter = 0;

class Counter {
public:
    Counter() {
        counter++;
    }
    ~Counter() {
        counter--;
    }
};

Counter test() {
    if (true) { // REMOVING THIS FIXES IT
        Counter c;
        return c;
    } else {
        throw std::logic_error("Impossible!");
    }
}

int main() {
    Counter c = test();
    std::cout << counter << std::endl; // 0 on GCC (incorrect), 1 on clang (correct)
    return 0;
}

In C++ returning an object from a function copy-constructs the object in the caller's context, then destroys the copied-from object, in the function being returned from. In some circumstances this copy can be elided.

       Counter c;
       return c;

This is named return value optimization and it is not mandatory in this case. Copy elision here is allowed, but it's optional. One of the compilers you used elides this copy, the other does not.

Without copy elision the compiler copy-constructs the returned object in the caller's context.

This Counter lacks a copy constructor, so the shown code fails to log an instance of the copy-constructed object.

Simply add a copy constructor:

class Counter {
public:
    Counter() {
        counter++;
    }
    Counter(const Counter &) {
        counter++;
    }
    ~Counter() {
        counter--;
    }
};

Now, you'll get the expected result, with or without copy elision.

If you set a breakpoint in the copy-constructor you'll see the breakpoint hit when returning from the function (when using the compiler that does not elide the copy).

The destructor is called at the end of the scope that has had objects in.

  1. When the first line - in main - excited, it will call test() .
  2. As you have put the condition true, it will create an object, which will increase counter by one.
  3. It will return c , but on the other hand, it's the end of the scope, which means that the destructor will be called, thus counter-- .

To be honest, I am not sure about my answer, but I think that what it is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM