1

I have a question about class variables and scopes in C++. Let's say I have the class below:

class TestClass {
public:
    std::vector<int> v;

    void foo()
    {
        v = std::vector<int>(10);
    }
}

Now, say I call the following code:

TestClass c;
c.foo();

When is the destructor of the vector (assigned to v) called? Is it called when foo() returns or when c goes out of scope?

Daniel
  • 383
  • 3
  • 13
  • 3
    Once when you assign v, and once again when c goes out of scope. – Ben Apr 16 '14 at 12:25
  • @Ben your first statement is wrong - `v`'s `operator=` will be called, not the destructor. That's one of the reasons you should always follow the rule of three.. – lethal-guitar Apr 16 '14 at 12:31
  • @lethal-guitar I think Ben means, a destructor is called after the line where the temporary is assigned to v. I also don't see what rule of three has to do here? – Neil Kirk Apr 16 '14 at 12:32
  • @NeilKirk assigning to an object will not call it's destructor, but the assignment operator - this is (in my experience) a source of confusion for many people when they are not familiar with the rule of three. – lethal-guitar Apr 16 '14 at 12:35

4 Answers4

2

v = std::vector<int>(10);

Temporary object is created, and then copied (or moved C++11) into v. After this line, temporary object's destructor is called.

When c goes out of scope, c.v's destructor is called.

Note: you can also do

v.resize(10);

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
2

Destructor for a member vector will be called when TestClass object destructor is called. It will happen when TestClass object goes out of scope

{
  TestClass c;
  c.foo();
} // destructor for c calls destructor for v

This is because C++ Standard 12.6.2 § 10:

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

— Then, non-static data members are initialized in the order they were declared in the class definition (again regardless of the order of the mem-initializers).

— Finally, the compound-statement of the constructor body is executed. 11 [ Note: The declaration order is mandated to ensure that base and member subobjects are destroyed in the reverse order of initialization. — end note ]

In line v = std::vector<int>(10) there will be also call to destructor for temporary object, because temporary vector std::vector<int>(10) is being created just to initialize v, and then it is destroyed.

4pie0
  • 29,204
  • 9
  • 82
  • 118
1

Okay, let's go through this step by step:

  • c is constructed, v is a member of c, so v must be constructed too.
  • foo is called
  • v is assigned a new value. The new value is constructed, old v is destructed, temporary vector is moved onto v. then moved or copied into v.
  • foo returns
  • c goes out of scope
  • c gets destructed, therefore v is also destructed.

So, v is destructed twice when c is destructed. The temporary may will also get destructed if we have no move constructor.

lethal-guitar
  • 4,438
  • 1
  • 20
  • 40
Ben
  • 1,816
  • 1
  • 20
  • 29
  • "old v is destructed" - *no, it's not*. The assignment will cause `vector::operator=()` to be invoked, but not it's destructor. Now with move semantics, the old "guts" will end up in the temporary, which will be destructed, so the effect is kind of the same - still, `V`'s destructor is definitely not called during the assignment. – lethal-guitar Apr 16 '14 at 12:37
  • @lethal-guitar Then when do we destroyed old v? – Ben Apr 16 '14 at 12:38
  • Never - keep in mind that `vector` is just a wrapper around dynamically allocated memory. This (the internal memory) will of course be destructed during the assignment/move, but the object `v` itself is only destructed when `c` goes out of scope. – lethal-guitar Apr 16 '14 at 12:40
  • @lethal-guitar That still doesn't make sense to me. What's the difference between destroying the "internal memory" of v and the object itself? Why are you grouping assignment and move together when they do completely different things? – Ben Apr 16 '14 at 12:45
  • "What's the difference between destroying the "internal memory" of v and the object itself?" The latter uses the destructor, the former doesn't (necessarily). – Neil Kirk Apr 16 '14 at 12:52
  • @Ben: The "internal memory": Every `std::vector` contains a member variable holding the dynamically allocated space for it's elements. When a `vector`'s assignment operator is called, it will destroy that memory, allocate new space and copy the contents of the assigned vector into that. For move assignment, it will switch it's memory pointer with the one in the rvalue, and when the rvalue is destroyed, the old memory will be destroyed as well. Now the `vector`'s dtor will also free the internal memory, but assignment doesn't involve destruction of the lvalue. – lethal-guitar Apr 16 '14 at 12:53
  • @Ben: Assignment and move assignment: They are different, but the net effect is the same: The lvalue (the object to which something is assigned) will end up with a different internal buffer than before. – lethal-guitar Apr 16 '14 at 12:55
  • So, dynamic memory is suppose to be destroyed in the assignment operator? – Ben Apr 16 '14 at 12:56
  • @Ben exactly. That's what the rule of three says: If your class needs a dtor, it also needs a copy ctor and an assignment operator. Otherwise it will leak memory/not work correctly/.. – lethal-guitar Apr 16 '14 at 12:58
  • @lethal-guitar If we replaced the assignment operator with a copy constructor in this example, would I be correct? – Ben Apr 16 '14 at 13:00
  • @Ben well, since `v` is already constructed it cannot be copy constructed again. You would be correct if `v` was a `unique_ptr>` instead. Then the smart pointer's assignment operator would delete the `vector`, which would call it's dtor. – lethal-guitar Apr 16 '14 at 13:02
  • @lethal-guitar Yeah, tested my own stuff, and I was leaking memory on assignments. Thanks for clearing that up. But why doesn't the destructor get called? Why make us clean up memory in two places? – Ben Apr 16 '14 at 13:09
  • 1
    @Ben you're welcome, C++ can be surprising at times. Well, there is a way you can avoid duplication: The copy&swap idiom, which is described in [this answer](http://stackoverflow.com/a/3279550/1451714), for example. – lethal-guitar Apr 16 '14 at 13:12
0

when your variable c goes out of scope destructor gets called automatically for c, which was automatically allocated, the destructor will take care of deleting the vector

Dr. Debasish Jana
  • 6,980
  • 4
  • 30
  • 69