Hi,

I've got a problem with a program that boils down to strange behavior by the vector container class. It seems to not want to call constructors enough but calls destructors too many times:

#include <vector>
#include <iostream>
using std::cout;

int constructor_count=1,destructor_count=1;

class obj{public:
	obj(){
		cout<<"C: "<<constructor_count++<<'\n';
	}	
	~obj(){
		cout<<"D: "<<destructor_count++<<'\n';
	}
};


int main(){
	cout<<"Declare v1:\n";
	std::vector<obj> v1(3);
	cout<<"\nResize v1:\n";
	v1.resize(4);
	cout<<"\n\nDeclare v2:\n";
	std::vector<obj> v2(3,obj());
	cout<<"\nResize v2:\n";
	v2.resize(4);
	std::cin.get();
}

/*Output:	-	-	-


Declare v1:
C: 1
D: 1

Resize v1:
C: 2
D: 2
D: 3
D: 4
D: 5
D: 6


Declare v2:
C: 3
D: 7

Resize v2:
C: 4
D: 8
D: 9
D: 10
D: 11
D: 12

*/

I was storing handles to window objects in a "wrapper class", and I got an error every time I resized the vector so that it needed to allocate more memory (ie it was fine if I called reserve(1000); at the start), and I've traced it down to this.

Is there any way to make the vector call the constructors properly?

Thanks for your help.

Hi,

I've got a problem with a program that boils down to strange behavior by the vector container class. It seems to not want to call constructors enough but calls destructors too many times:

#include <vector>
#include <iostream>
using std::cout;

int constructor_count=1,destructor_count=1;

class obj{public:
	obj(){
		cout<<"C: "<<constructor_count++<<'\n';
	}	
	~obj(){
		cout<<"D: "<<destructor_count++<<'\n';
	}
};


int main(){
	cout<<"Declare v1:\n";
	std::vector<obj> v1(3);
	cout<<"\nResize v1:\n";
	v1.resize(4);
	cout<<"\n\nDeclare v2:\n";
	std::vector<obj> v2(3,obj());
	cout<<"\nResize v2:\n";
	v2.resize(4);
	std::cin.get();
}

/*Output:	-	-	-


Declare v1:
C: 1
D: 1

Resize v1:
C: 2
D: 2
D: 3
D: 4
D: 5
D: 6


Declare v2:
C: 3
D: 7

Resize v2:
C: 4
D: 8
D: 9
D: 10
D: 11
D: 12

*/

I was storing handles to window objects in a "wrapper class", and I got an error every time I resized the vector so that it needed to allocate more memory (ie it was fine if I called reserve(1000); at the start), and I've traced it down to this.

Is there any way to make the vector call the constructors properly?

Thanks for your help.

I ran your codes in DEV-C++ ,the calls to constructors are proper.
Which compiler did you use?

A good implementation of the vector would call the copy constructor when memory is reallocated. Invoking the default constructor first and then the assignment operator has an efficiency issue.
Note: C++0x containers would use move semantics (instead of copy semantics) if they are available on the object.

Modify the code to

int constructor_count=1,destructor_count=1;

class obj{public:
	obj(){
		cout<<"C: "<<constructor_count++<<'\n';
	}	
        
         obj( const obj& ){
		cout<<"C: "<< constructor_count++<<'\n';
	}	
	~obj(){
		cout<<"D: "<<destructor_count++<<'\n';
	}
};

and you would find that calls to constructors and destructors are matched perfectly.

> I was storing handles to window objects in a "wrapper class", and I
> got an error every time I resized the vector so that it needed to
> allocate more memory (ie it was fine if I called reserve(1000);
> at the start), and I've traced it down to this.

Make sure that your wrapper class does have a correct copy constructor and a correct overloaded assignment operator (hint: you need to keep a count of how many handles refer to a window). And the problem will go away.

Edited 6 Years Ago by vijayan121: n/a

Hi,

I'm using VC++ 2008. I think I understand what's going on now: When you declare the vector, it constructs one object, makes n copies of it, then for some reason destroys the original object; when you resize it, it copies the existing objects, destroys the original and uses the same procedure to create new objects.:?:

Thank you very much for your help.

#include <vector>
#include <iostream>
using std::cout;

int constructor_count=1,copy_count=1,destructor_count=1;

class obj{public:
	obj(){
		cout<<"C: "<<constructor_count++<<"\t@\t"<<this<<'\n';
	}
	obj(const obj& c){
		cout<<"P: "<<copy_count++<<"\tfrom\t"<<&c<<"\tto\t"<<this<<'\n';
	}
	~obj(){
		cout<<"D: "<<destructor_count++<<"\t@\t"<<this<<'\n';
	}
};


int main(){
	cout<<"Declare v1:\n";
	std::vector<obj> v1(3);
	cout<<"\nResize v1:\n";
	v1.resize(4);
	cout<<"\n\nDeclare v2:\n";
	std::vector<obj> v2(3,obj());
	cout<<"\nResize v2:\n";
	v2.resize(4);
	std::cin.get();
}

/*Output

Declare v1:
C: 1	@	0012FD57
P: 1	from	0012FD57	to	00346598
P: 2	from	0012FD57	to	00346599
P: 3	from	0012FD57	to	0034659A
D: 1	@	0012FD57

Resize v1:
C: 2	@	0012FD48
P: 4	from	0012FD48	to	003465CB
P: 5	from	00346598	to	003465C8
P: 6	from	00346599	to	003465C9
P: 7	from	0034659A	to	003465CA
D: 2	@	00346598
D: 3	@	00346599
D: 4	@	0034659A
D: 5	@	0012FD48


Declare v2:
C: 3	@	0012FE5F
P: 8	from	0012FE5F	to	00346598
P: 9	from	0012FE5F	to	00346599
P: 10	from	0012FE5F	to	0034659A
D: 6	@	0012FE5F

Resize v2:
C: 4	@	0012FD48
P: 11	from	0012FD48	to	003465FB
P: 12	from	00346598	to	003465F8
P: 13	from	00346599	to	003465F9
P: 14	from	0034659A	to	003465FA
D: 7	@	00346598
D: 8	@	00346599
D: 9	@	0034659A
D: 10	@	0012FD48

*/

I ran your codes in DEV-C++ ,the calls to constructors are proper.
Which compiler did you use?

Make sure that your wrapper class does have a correct copy constructor and a correct overloaded assignment operator (hint: you need to keep a count of how many handles refer to a window). And the problem will go away.

I'm actually scared of vectors now - I think it's probably safer go back to using arrays, or maybe write my own vector class.

> it constructs one object, makes n copies of it,
> then for some reason destroys the original object

That is the way it is expected to work. The relevant constructor is

explicit vector( size_type n, const T& value = T(), 
                 const Allocator& = Allocator() ) ;

For the second argument, a temporary T is default constructed, the n elements in the vector are then copy constructed from this temporary, and the temporary is then destroyed. A clever compiler may save a small bit of time by applying the optimization as allowed in IS 12.8/15.

> when you resize it, it copies the existing objects, destroys the
> original and uses the same procedure to create new objects.

The reason is identical. If you look at the declaration of resize, you can see where the temporary object comes from.

void resize( size_type sz, T c = T() ) ;

> I'm actually scared of vectors now - I think it's probably safer go
> back to using arrays, or maybe write my own vector class.

There is no reason to be scared of vectors. I'm scared of arrays unless I know the size of the array at compile time. Just make sure that the type of the element in a sequence container is copy constructable and assignable.

The problem is with your wrapper class, not with the vector. If you refuse to face it by avoiding use of a vector here, it will just surface somewhere else - for example when you have your wrapper class as a member of another class.

Comments
Nice
This article has been dead for over six months. Start a new discussion instead.