Sign in to follow this  
indigox3

STL vectors and operator delete

Recommended Posts

Hi Say I have the following:
class B
{

};

class A 
{
public:
std::vector< B > mBs;
};

class C
{
public:
	std::vector< A > mAs;
};

main()
{
	A aa;
	{
		B bb;
		aa.mBs.push_back( bb );
	}

	C* cc = new C;
	cc->mAs.push_back( aa );
	
	delete cc; // STL code is calling delete on elements of the aa's 
}

This pretty much does what you would expect. However, I have some real code similar to this, and delete is getting called (in the bowels of the STL code) on the B elements of A::mBs, when delete is called on cc. This causes a crash (probably because the elements of the vector are stack allocated objects) Why would delete be called on the elements of A::mBs?

Share this post


Link to post
Share on other sites
The elements aren't stack allocated. The vector contains copies of the original values. Furthermore, while the elements' destructors get called when the vector is destroyed, delete isn't "called" on them.

Share this post


Link to post
Share on other sites
I agree that the vector contains copies of the elements I am putting into it. However I'm not sure if the copies created on the stack or heap. (Probably heap thinking about it...)

Along those lines, ~vector() calls _Tidy() calls allocator::deallocate() calls delete with the pointer to the first element of the vector as an argument.

Must be something else going wrong then, I'll keep looking.

Thanks

Share this post


Link to post
Share on other sites
Quote:
Original post by indigox3
I agree that the vector contains copies of the elements I am putting into it. However I'm not sure if the copies created on the stack or heap. (Probably heap thinking about it...)

vector, and all dynamic containers (with the occasional exception of std::string in some implementations), only ever allocate on the heap.

Post your actual code, and we may be able to help.

Share this post


Link to post
Share on other sites
From the sound of it you got a double delete bug comming from not the STL but missing copy and assignment operators in your own classes that probably have some sort of resource (like a pointer to dynamicly allocated memory).

Share this post


Link to post
Share on other sites
Quote:
Original post by indigox3
I agree that the vector contains copies of the elements I am putting into it. However I'm not sure if the copies created on the stack or heap. (Probably heap thinking about it...)

Along those lines, ~vector() calls _Tidy() calls allocator::deallocate() calls delete with the pointer to the first element of the vector as an argument.

Must be something else going wrong then, I'll keep looking.



The allocator's allocate/deallocate methods deals solely with uninitialized memory. The default allocator (std::allocator) uses global operators new/delete via explicit invocation this gives/returns uninitialized memory, allocator's construst/destroy deal soley with de/initialization of uninitialized memory.

Typically (it is imp defined) std::vector is implementated with RAII techniques, std::vector may have a non-polymorphic base that deals with allocation and deallocation in the base destructor, then std::vector just destroys elements in its destructor after which the base deallocates memory.

Quote:
Original post by Sneftel
... only ever allocate on the heap.


Never say never [grin], std::allocator uses heap but give them a custom allocator type that can use what ever you want [wink].

Share this post


Link to post
Share on other sites
I can't post the actual code because of IP issues, but I did comment out pratically everything that could be giving me problems and the code boils down to:

class A : public B
{
public:
std::vector< int > mInts;
A(){};
~A(){};
};

main()
{
A* a = new A();

a->mInts.push_back(12);

...

HomeGrownVector v;
v.push( a );

...

for( int i = 0; i < v.size(); i++)
delete v[i]; // dies here where A::mInts is destroyed.

}

I'm sure "a" isnt being deleted twice, bc I'm breaking on ~A() and its only getting called once.

The homegrown vector might be doing something weird, I'll have to check.

Share this post


Link to post
Share on other sites
You must not delete elements you did not allocate using new. Since you never allocated the elements of v on the heap you must not delete them. just delete a, that will free all memory in your example.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by snk_kid
The allocator's allocate/deallocate methods deals solely with uninitialized memory. The default allocator (std::allocator) uses global operators new/delete via explicit invocation this gives/returns uninitialized memory, allocator's construst/destroy deal soley with de/initialization of uninitialized memory.

Typically (it is imp defined) std::vector is implementated with RAII techniques, std::vector may have a non-polymorphic base that deals with allocation and deallocation in the base destructor, then std::vector just destroys elements in its destructor after which the base deallocates memory.


Wow - what a lot to say very little, still it probably felt intelligent at the time.

More simply, vectors allocate and deallocate memory as required.

If adding objects to a vector like in your example, the vector will allocate memory (on the heap using new) and make copies of your objects. Unless you're using a very old implementation of STL that contains such a bug, it's not a bug in STL. Certainly not one i've encountered anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by VolkerG
You must not delete elements you did not allocate using new. Since you never allocated the elements of v on the heap you must not delete them. just delete a, that will free all memory in your example.


Oops, I should have been more clear:
the v[i]'s are pointers, one of which, is the same as "a".

In other words v is a vector of pointers, not objects

Share this post


Link to post
Share on other sites
Quote:
Original post by indigox3
In other words v is a vector of pointers, not objects


Well, pointers don't have destructors, so nothing happens to what they point to when the vector and its elements get destroyed.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Wow - what a lot to say very little, still it probably felt intelligent at the time.

More simply, vectors allocate and deallocate memory as required.

If adding objects to a vector like in your example, the vector will allocate memory (on the heap using new) and make copies of your objects. Unless you're using a very old implementation of STL that contains such a bug, it's not a bug in STL. Certainly not one i've encountered anyway.


[headshake][rolleyes] what babbling off-topic rubbish are you on about? not that it is any of your business but i was trying to explain something to indigox3 in reference to this:

Quote:
Original post by indigox3
Along those lines, ~vector() calls _Tidy() calls allocator::deallocate() calls delete with the pointer to the first element of the vector as an argument.


As to what was going on. The default allocator's (std::allocator) deallocate method doesn't implicitly invoke delete like people normally do because that would also destroy aswell as deallocate elements, the allocator concept separates allocation/deallocation & construction/destruction for efficiency reasons.

Share this post


Link to post
Share on other sites
Quote:
Original post by Fruny
Quote:
Original post by indigox3
In other words v is a vector of pointers, not objects


Well, pointers don't have destructors, so nothing happens to what they point to when the vector and its elements get destroyed.


I'm totally confused by this. operator delete takes only pointers as arguments.
I know the destructor is being called because I am setting breakpoints up in my debugger and I am breaking in the destructor, although maybe I am not understanding you.


I even brought the code downto


class A : public B
{
public:
A(){}
~A(){}
std::vector<int> mInt;
};

main()
{

A* a = new A();

a->mInt.push_back(12);

delete a;

}


and I *still* crash.... I'm totally stumped..

Oddly, if I comment out a->mInt.push_back(12) I dont get a crash

Share this post


Link to post
Share on other sites
Quote:
Original post by indigox3
Quote:
Original post by Fruny
Quote:
Original post by indigox3
In other words v is a vector of pointers, not objects


Well, pointers don't have destructors, so nothing happens to what they point to when the vector and its elements get destroyed.


I'm totally confused by this. operator delete takes only pointers as arguments.


Right, but when you call delete on a pointer it deletes (and potentially calls the destructor of) the pointed to object, not the pointer. You can try to delete an actual pointer if you call delete on the address of the pointer, but the destructor of the pointer is a no-op. Ex:

#include <iostream>

class Boring {
public:
Boring() { std::cout << "Construct me!" << std::endl; }
Boring(const Boring &) { std::cout << "Construct me!" << std::endl; }
~Boring() { std::cout << "Destroy me!" << std::endl; }
};


int main(int, char **) {
Boring ** pointer_to_pointer = new Boring *; // creates a new Boring pointer
*pointer_to_pointer = new Boring; // creates a new Boring

delete pointer_to_pointer; // deletes the pointer, does nothing to the Boring
// and causes a mem leak

return 0;
}

As you can see, deleting the pointer does nothing to delete the object pointed to by the pointer.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
As you can see, deleting the pointer does nothing to delete the object pointed to by the pointer.


Ah, ok I see what you mean now. I made sure I am using:


delete pointer;


and not


delete pointer_to_pointer;

Share this post


Link to post
Share on other sites
Anyone know if there can be problems using the stl vector from a library?

The code I have is all defined in a library which is compiled to a DLL. I wrote a new class that does not inhierit from anything inside the DLL, but is still defined within the DLL.


class __declspec( dllexport ) A // forgot the "__declspec(dllexport)" last time!
{
public:
A();
~A();
std::vector<int> aaa;

void push()
{
aaa.push_back(1);
}

};



Then, I am linking to the lib from a visual studio.net 2003 project, and doing:


int func()
{
A* a = new A;
a->aaa.push_back(1);
//a->push(); // if this line is used instead of the above line no crash
delete a; //crash here.
}


Is it possible that the vector is allocating memory differently when push_back is called from the application, as opposed to the DLL?
or are there some other gotchas with using DLLs that I am unaware of?

Share this post


Link to post
Share on other sites
C++ + DLL's = Bad Mojo

There are so many different things that can go wrong when using classes from a DLL that it's not even funny. The two most likely problems with what you seem to be trying to do are: one, the DLL and the application are using different heaps. To fix that is compiler dependent, but for MSVC, you need to make sure that both the DLL and the executable are using the a DLL version of the runtime library. (Either the /MD or /MDd switch). The second possiblity is that you need to properly export the vector class. To that, see this article on using templates with DLLs.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
C++ + DLL's = Bad Mojo



Agreed. Right now I am wrapping the vector calls with simple Push/Size/Get/etc methods and using other methods in the DLL to handle the allocation/deallocation of memory to avoid this problem. Everything seems to be working now.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this