2

I want to seek help on this issue I encountered when learning C++. I tried to store objects into an array directly, but realize the objects gets deconstructed right away. I could not figure out why exactly is this so.

#include <iostream>

class Thing{
    public:
    ~Thing(){
        std::cout<<"Thing destructing";
    }
};

int main(){
    Thing arr[1];
    arr[0] = Thing();
    int x;
    std::cin>>x;
};
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Kay.Z
  • 43
  • 4
  • 6
    `Thing();` creates a temporary object which is then copied/moved into the array. The temporary object has to be destroyed – UnholySheep Nov 08 '21 at 16:04
  • When you get a problem like this also add the copy constructor and the assignment operator so you can see everything that's going in. In general, if your class needs a destructor, it also needs a copy constructor and an assignment operator. This is part of what is often called the [Rule of Three](https://en.cppreference.com/w/cpp/language/rule_of_three). – user4581301 Nov 08 '21 at 16:08
  • 1
    If you're coming to C++ from C# or Java, a big difference is that C# and Java use heap allocation and garbage collection as default, where an assignment keeps the original allocation, while C++ defaults to local (stack) allocation and copying). Pointers can be used in C++, but without garbage collection they are harder to get right so are mostly avoided. – John Bayko Nov 08 '21 at 16:18
  • Perhaps related: In `arr[0] = Thing();`: Why do you even replace the default constructed `Thing` in the array with a new default constructed `Thing`? – Ted Lyngmo Nov 08 '21 at 16:33

2 Answers2

3

In this statement

arr[0] = Thing();

there is used the default copy assignment operator that assigns the temporary object created by this expression Thing() to the element of the array. After the assignment the temporary object is destroyed.

To make it more clear run this demonstration program.

#include <iostream>

class Thing
{
public:
    ~Thing()
    {
        std::cout<<"Thing " << i << " destructing\n";
    }
    
    Thing & operator =( const Thing & )
    {
        std::cout << "Thing " << i << " assigning\n";
        return *this;
    }
    
    Thing() : i( ++n )
    {
        std::cout << "Thing " << i << " constructing\n";
    }

private:    
    size_t i;
    static size_t n;
};

size_t Thing::n = 0;

int main() 
{
    {
        Thing arr[1];
        arr[0] = Thing();
    }
    
    std::cin.get();
    
    return 0;
}

Its output is

Thing 1 constructing
Thing 2 constructing
Thing 1 assigning
Thing 2 destructing
Thing 1 destructing
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

Assuming you don't know already.

Smart-Pointer

#include <memory>

// ...

int main() {
    std::shared_ptr<Thing> arr[1];
    arr[0] = std::shared_ptr<Thing>(new Thing());

    // ...

    // <-- Is automatically deleted around here.
}

Pointer

Not-Recommended; Using pointer would look like:

int main() {
    Thing *arr[1] = {};
    arr[0] = new Thing();

    int x;
    std::cin >> x;

    // WARNING: remember to manually delete.
    delete arr[0];
} // <-- BTW, you don't need semi-colon.
Top-Master
  • 7,611
  • 5
  • 39
  • 71