Why does the [] operator in vector behave as it does?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I am using the g++ (GCC) 4.1.3 version of the compiler, which I have installed under ubuntu gutsy, and compile from my eclipse cdt IDE.

I have started a c++ project in which I wish to use the vector template to store objects (say class A) which contain pointers to other objects on the heap, and I occasionally want to replace entries in my vector. So I want my old entry to be destroyed, and a new entry to be added. Moreover, I read access this object referenced by index much more often and hence prefer the vector over a map, for instance.

I have tried to explain with a short pseudo-code example, please see attached file for a more detailed example of this as a .cpp file.

Example:
Consider I have a vector of n objects of type A, all initialised in some way, and a new object type A (called a_new) that I wish to insert in the vector at the i_th position (replacing the old contents). So with

unsigned int n = 3, i=1;
vector<A> vec = vector<A>(n,A(0));
A a_new = A(1);

My first thought was to do this to replace things.

vec[i] = a_new;

But a_new's destructor is called when a_new goes out of scope and this is referenced by vec[i], hence vec[i] no longer points to a valid place in memory. In other words our A(1) object only exists in this scope.

I know this was stupid, but by these ways do we learn. So next I tried creating an object on the heap and referencing this with vec[i]. This required a copy constructor for A, but no problem.

vec[i] = *(new A(a_new));

This worked, and what is more when I called vec.clear() this object was destroyed. One would assume that I was then happy. But in checking the destructor I discovered that the original object at vec[i] (the A(0) object) did not call its own destructor.

Even if this object was destroyed in some other way by the vector, by deallocating the memory in some low level way. It doesn't do any of the cleaning up I require, since in my case my A objects themselves have pointers to the heap, and this indirect memory usage is not being deallocated.

Finally, I tried (in desperation)

A* tmp = &(vec[i]);
vec[i] = *(new A(a_new));
delete tmp;

This unsurprisingly called the destructor on tmp, but in the process the vec[i] reference became invalid, in other words at the delete command, tmp was pointing to the same object as vec[i].

As I said above, I have attached a .cpp file with this behaviour shown in more detail. Am I missing something, or is this behaviour somehow not correct? If it is correct then shouldn't the [] operator only return a 'const reference' instead of a reference. I apologise if this is an idiotic question.

Luke

#include <iostream>
#include <vector>

using namespace std;
/*
 *  Class A is a simple object with an id, it is
 *  sometimes shared between a number of objects.
 */
class A {
	
	int* id;

public:
	A(){ 
		cout << "debug: called A::A()" << endl; 
		id = new int(-1); 
		output();
	};
	A(unsigned int in){
		cout << "debug: called A::A(unsigned int)" << endl; 
		id = new int((int)(in));
		output();
	};
	A(const A& orig){
		cout << "debug: called A::A(const A&)" << endl; 
		id = new int(*(orig.id));
		output();
	};
	virtual ~A(){
		cout << "debug: called A::~A()" << endl; 
		output();
		delete id;
	};
	
	void output(){
		cout << "id ::(val,address) = (" << *id << "," << id << ")" << endl;
	}
};


int main(){
	cout << "********************************************" << endl;
	cout << "* Initialising vectors and shared A object *" << endl;
	cout << "********************************************" << endl;
	const unsigned int SIZE = 3;
	const unsigned int POS = SIZE-2;
	const unsigned int ID1 = 1; 
	const unsigned int ID2 = 2;
	vector<A> vec = vector<A>(SIZE,A(ID1));
	cout << endl;
	cout << endl;
	cout << endl;

	cout << "************************" << endl;
	cout << "* Replacing an element *" << endl;
	cout << "************************" << endl;
	try {
		cout << "Before replace:" << endl;
		for( unsigned int i = 0 ; i	< SIZE ; ++i ) {
			vec[i].output();			
		}
		cout << endl;

		vec[POS] = *(new A(ID2));

		cout << "After replacing:" << endl;
		for( unsigned int i = 0 ; i	< SIZE ; ++i ) {
			vec[i].output();			
		}
		cout << endl;
	} catch (exception e) {
		cout << "error: vec output failed" << endl;	
	}	

	cout << "***********************" << endl;
	cout << "* Swapping an element *" << endl;
	cout << "***********************" << endl;
	try {
		cout << "Before swapping:" << endl;
		for( unsigned int i = 0 ; i	< SIZE ; ++i ) {
			vec[i].output();			
		}
		cout << endl;

		A* tmp = &(vec[POS]);
		vec[POS] = *(new A(ID2));
		delete tmp;

		cout << "After replacing:" << endl;
		for( unsigned int i = 0 ; i	< SIZE ; ++i ) {
			vec[i].output();			
		}
		cout << endl;
	} catch (exception e) {
		cout << "error: vec output failed" << endl;	
	}	
	cout << endl;
	cout << endl;
	cout << endl;

	cout << "*************************" << endl;
	cout << "* Clearing both vectors *" << endl;
	cout << "*************************" << endl;
	vec.clear();
	cout << endl;
	cout << endl;
	cout << endl;
	return 0;
}

[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux