Destructors being called more then expected?

In this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma once
#include <iostream>
        
class CBox        // Derived class
{
  public:
 
        
    // Constructor
    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) : m_Length(lv), m_Width(wv), m_Height(hv){}

    ~CBox()
    { std::cout << "CBox destructor called" << std::endl; }

  protected:
    double m_Length;
    double m_Width;
    double m_Height;
};
  
#include <vector>
using namespace std;

int main()
{
	auto boxes = vector<CBox>();

boxes.push_back(CBox(1, 2, 3));
boxes.push_back(CBox(2, 4, 6));
boxes.push_back(CBox(3, 6, 9));

  return 0;
}


Before the program ends, at return 0;

I would expect the CBox destructor to be called 3 times but it is being called 6 times? Why?


Also in this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma once
#include <iostream>
        
class CBox        // Derived class
{
  public:
 
        
    // Constructor
    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) : m_Length(lv), m_Width(wv), m_Height(hv){}

    ~CBox()
    { std::cout << "CBox destructor called" << std::endl; }

  protected:
    double m_Length;
    double m_Width;
    double m_Height;
};
  
#include <vector>
using namespace std;

int main()
{
	auto boxes = vector<CBox>();

boxes.emplace_back(1, 2, 3);
boxes.emplace_back(2, 4, 6);
boxes.emplace_back(3, 6, 9);

  return 0;
}


Why is the destructor called 3 times? When have you really destroyed a CBox? Doesnt emplace only create it and store it, then thats it?

http://msdn.microsoft.com/en-CA/library/dd647616.aspx
http://msdn.microsoft.com/en-us/library/7fthz5xd.aspx

msdn doesnt provide much help for either, I tried looking at the library code itself but I dont exactly understand it lol.


For pushback:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void push_back(value_type&& _Val)
		{	// insert by moving into element at end
		if (_Inside(_STD addressof(_Val)))
			{	// push back an element
			size_type _Idx = _STD addressof(_Val) - this->_Myfirst;
			if (this->_Mylast == this->_Myend)
				_Reserve(1);
			_Orphan_range(this->_Mylast, this->_Mylast);
			this->_Getal().construct(this->_Mylast,
				_STD forward<value_type>(this->_Myfirst[_Idx]));
			++this->_Mylast;
			}
		else
			{	// push back a non-element
			if (this->_Mylast == this->_Myend)
				_Reserve(1);
			_Orphan_range(this->_Mylast, this->_Mylast);
			this->_Getal().construct(this->_Mylast,
				_STD forward<value_type>(_Val));
			++this->_Mylast;
			}
		}


Emplace

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#define _VECTOR_EMPLACE( \
	TEMPLATE_LIST, PADDING_LIST, LIST, COMMA, X1, X2, X3, X4) \
	TEMPLATE_LIST(_CLASS_TYPE) \
		void emplace_back(LIST(_TYPE_REFREF_ARG)) \
		{	/* insert by moving into element at end */ \
		if (this->_Mylast == this->_Myend) \
			_Reserve(1); \
		_Orphan_range(this->_Mylast, this->_Mylast); \
		this->_Getal().construct(this->_Mylast COMMA LIST(_FORWARD_ARG)); \
		++this->_Mylast; \
		} \
	TEMPLATE_LIST(_CLASS_TYPE) \
		iterator emplace(const_iterator _Where \
			COMMA LIST(_TYPE_REFREF_ARG)) \
		{	/* insert by moving _Val at _Where */ \
		size_type _Off = _VIPTR(_Where) - this->_Myfirst; \
		_VECTOR_EMPLACE_CHECK \
		emplace_back(LIST(_FORWARD_ARG)); \
		_STD rotate(begin() + _Off, end() - 1, end()); \
		return (begin() + _Off); \
		} 



Thanks to anyone who helps, hope I provided enough information.
Last edited on
boxes.push_back(CBox(1, 2, 3));
This pushes a copy of CBox. You do it 3 times, 6 objects.
Anmol444 wrote:
Why is the destructor called 3 times? When have you really destroyed a CBox? Doesnt emplace only create it and store it, then thats it?
The objects in the vector will be destructed when the vector goes out of scope, at the end of main.
I revised your code and this shows you that the objects are destructed properly.

InvaDev
http://www.invadev.com


#ifndef __CBOX__
#define __CBOX__

#include <iostream>
class CBox        // Derived class
{
  public:
 
        
    // Constructor
    explicit CBox(
	double lv = 1.0, 
	double wv = 1.0, 
	double hv = 1.0) : m_Length(lv), m_Width(wv), m_Height(hv){}

    ~CBox()
    {
	std::cout << "CBox destructor called" << std::endl;
    }

  protected:
    double m_Length;
    double m_Width;
    double m_Height;
};

#endif //__CBOX__

#include <vector>
using namespace std;

int main()
{
	vector<CBox*> boxes;

	boxes.push_back(new CBox(1, 2, 3));
	boxes.push_back(new CBox(2, 4, 6));
	boxes.push_back(new CBox(3, 6, 9));
	
	for(int i = 0; i < boxes.size();i++)
	{
		delete boxes[i];
	}
	
  return 0;
}
cired wrote:
I revised your code and this shows you that the objects are destructed properly.


In the process you leaked 3 CBox objects whose destructors are not called. In a sense, your code does the opposite of what you claim. [edit: Actually I didn't look closely enough at your code in the output tags -- the code is fine (would be better with std::unique_ptr), but it doesn't illustrate anything.]

@OP:
When you push_back(CBox(1,2,3)) you create a temporary CBox object which is copied into the vector. The temporary's constructor is invoked immediately after push_back returns.

I wouldn't expect that of emplace back. A little experimentation leads me to believe emplace_back is not implemented correctly for contained objects that are copy- but not move-constructable. GCC doesn't display the same behavior.

If you define a move constructor for your class I think you'll see the expected behavior, although it shouldn't be necessary.

[Edit: Doesn't seem to be a bug report on Microsoft Connect - I'll submit one when I have more time if nobody beats me to it.]
Last edited on
@cire

I know about the 3 first calls, but what about the 3 other calls that make it 6?

(its actually nine if you count when the program ends and all their destructors are called)


Maybe the way both of them insert the CBox involves copying it once?

I dont know what else to say.


Alright let me check, gonna implement it.

Last edited on
Wait but how would the move constructor really work? There isn't much effort in constructing or deconstructing the CBox so I am a bit confused. You cant really "move" a CBox?
Also cired vs cire?

lol that confused me for a second.
I know about the 3 first calls, but what about the 3 other calls that make it 6?


In the push_back code there should be 6. The three temporaries that are destroyed when their respective push_backs return, and the three stored in the vector that are destroyed when the vector goes out of scope. Using emplace_back, there should be 3.

Wait but how would the move constructor really work? There isn't much effort in constructing or deconstructing the CBox so I am a bit confused. You cant really "move" a CBox?

In this case the move constructor would look exactly like the copy constructor with the obvious exception of the parameter type. As I said, it shouldn't be required to get the expected behavior with emplace_back, but apparently with VC++ it is.
@Cire

By the time the vector is destroyed there are 9 not 6?

In this code it has a move constructor but it still has 3 with emplace_back (before vector is destroyed)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#pragma once
#include <iostream>
        
class CBox      
{
  public:
 
        
    // Constructor
    explicit CBox(double lv = 1.0, double wv = 1.0, double hv = 1.0) : m_Length(lv), m_Width(wv), m_Height(hv){}

	   // Move Copy Constructor
    explicit CBox(CBox &&box)
	{

		m_Length=box.m_Length;
		m_Width=box.m_Width;
		m_Height=box.m_Height;
	
	}

    ~CBox()
    { std::cout << "CBox destructor called" << std::endl; }

  protected:
    double m_Length;
    double m_Width;
    double m_Height;
};
  
#include <vector>
using namespace std;

int main()
{
	auto boxes = vector<CBox>();

boxes.emplace_back(1, 2, 3);
boxes.emplace_back(2, 4, 6);
boxes.emplace_back(3, 6, 9);

  return 0;
}




Also every time I mentioned a number of how many destructors were called, I meant it before return 0; before it was destroyed.

6 are called before that for push_back

3 are called before that for emplace_back

And ofcourse you could add another 3 for when vectors are destroyed.
Last edited on
The extra destructor calls happens when the vector has to reallocate.
Yar. I stuck a reserve in there, so it wasn't happening for me.
So true thanks Peter87.

and thanks cire!
Last edited on
Topic archived. No new replies allowed.