Sign in to follow this  
Raeldor

Ouch! Exception During Realloc of Dynamic Array of Smart Pointers

Recommended Posts

I seem to be getting a heap error from the C run time library when trying to do a re-alloc on a section of memory that holds an array of smart pointers. Can anyone tell me what effect this should have on my smart pointers? I assumed that it would just do some kind of memory copy and that none of my smart pointer constructor/destructor logic should get called, and that everything would be ok (just in a different location). Is there something else going on here I am unaware of? Thanks

Share this post


Link to post
Share on other sites
Was the memory allocated by malloc, calloc or realloc? Are the smart pointers POD types? If the answer to either of these questions is no then you shouldn't be using realloc. In fact in my opinion you shouldn't be using realloc even if the answer to both those questions is yes - you should be using a std::vector or other container instead.

Enigma

Share this post


Link to post
Share on other sites
Quote:
Original post by Enigma
Was the memory allocated by malloc, calloc or realloc? Are the smart pointers POD types? If the answer to either of these questions is no then you shouldn't be using realloc. In fact in my opinion you shouldn't be using realloc even if the answer to both those questions is yes - you should be using a std::vector or other container instead.

Enigma


It was allocated by malloc. Can you tell me what you mean by POD type?

Thanks

Share this post


Link to post
Share on other sites
I think I am narrowing down my problem a little here. My biggest issue at the moment seems to be the destruction of the dynamic array class.

At the moment the class destructor just does...

~DynamicArray()
{
// now free array
free(m_array);
}


This means if it is holding a list of smart pointers, that the reference count is not getting released. I can't just go through and do...

// first delete items
for (int i=0; i < m_count; i++)
m_array[i]=NULL;


because because there is no guarantee that the class is holding a list of pointers.

How have others overcome this problem?

Thanks

Share this post


Link to post
Share on other sites
Make a templated, type safe, dynamic array, and use new and delete for resizing it.

Or, use one of the standard library dynamic containers; std::vector if you want continious memory.

Share this post


Link to post
Share on other sites
Quote:
Original post by c2_0
Make a templated, type safe, dynamic array, and use new and delete for resizing it.

Or, use one of the standard library dynamic containers; std::vector if you want continious memory.


Cool. I changed my mallocs and frees to 'new' and 'delete []'. It seems to work great now. For the array resize, I had to use...

// create new array
m_arraySize+=m_growBy;
T* newArray=new T[m_arraySize];

// copy members
for (int i=0; i < m_count; i++)
newArray[i]=m_array[i];

// delete old array and replace
delete [] m_array;
m_array=newArray;


which seems to work, but may not be the most efficient?

Thanks!

Share this post


Link to post
Share on other sites

template<typename T>
class DynamicArray
{
protected:
int m_size;
T* m_pBuffer;

public:
DynamicArray() : m_pBuffer(NULL), m_size(0)
{
}

DynamicArray(int size) : m_pBuffer(NULL), m_size(0)
{
Create(size);
}

~DynamicArray()
{
if (m_pBuffer)
delete [] m_pBuffer;
}

void Create(int size)
{
assert(!m_pBuffer && "Array already created");
m_size = size;
m_pBuffer = new T[size];
}

void Resize(int size)
{
int copySize = min(size, m_size);
T* pDest = new T[size];
T* pSrc = m_pBuffer;
T* pOriginal = m_pBuffer;

m_pBuffer = pDest;
m_size = size;

while (copySize--)
*(pDest++) = *(pSrc++);

delete [] pOriginal;
}

int GetSize()
{
return m_size;
}

operator T*()
{
return m_pBuffer;
}

T* DataPtr()
{
return m_pBuffer;
}

const T& operator [](int index) const
{
assert((index >= 0) && (index < m_size) && "Index out of range!");
return m_pBuffer[index];
}

T& operator [](int index)
{
assert((index >= 0) && (index < m_size) && "Index out of range!");
return m_pBuffer[index];
}
};




[Edited by - e-u-l-o-g-y on September 6, 2005 5:18:43 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by e-u-l-o-g-y
*** Source Snippet Removed ***


Am I missing something? How is that dynamic? How does the array re-size itself?

Share this post


Link to post
Share on other sites
Quote:
Original post by Raeldor
Quote:
Original post by c2_0
Make a templated, type safe, dynamic array, and use new and delete for resizing it.

Or, use one of the standard library dynamic containers; std::vector if you want continious memory.


Cool. I changed my mallocs and frees to 'new' and 'delete []'. It seems to work great now. For the array resize, I had to use...
*** Source Snippet Removed ***
which seems to work, but may not be the most efficient?

Thanks!


To be efficient you'd need to use something like std::uninitialized_copy() and manipulate raw memory. This is not something that's worth time worrying about when std::vector does it for you.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
To be efficient you'd need to use something like std::uninitialized_copy() and manipulate raw memory. This is not something that's worth time worrying about when std::vector does it for you.


Quoted for emphasis.

Share this post


Link to post
Share on other sites
I've just edited the class and added a resize member.. the reason why I took out the resize member was that I didn't really need it. I use a vector for dynamic arrays with varying size, and this class for dynamic arrays that stay the same once sized.

Share this post


Link to post
Share on other sites
Quote:
Original post by e-u-l-o-g-y:
void Resize(int size)
{
int copySize = min(size, m_size);
T* pDest = new T[size];
T* pSrc = m_pBuffer;
m_pBuffer = pDest;
m_size = size;
while (copySize--)
*(pDest++) = *(pSrc++);
}

Nice memory leak and corrupts the container if a copy constructor throws (some objects will be lost). Just use std::vector (or another suitable container).

Enigma

Share this post


Link to post
Share on other sites
Seriously, why aren't you using std::vector?

It is:

easier
faster (really, these guys write containers for a living, you don't)
easier to get help on, that is if you need help
feature complete (or at least much closer than whatever you are making)

the downside: you'll have to swallow your pride and maybe get used to some of the function names being different from what you would have named them.

Share this post


Link to post
Share on other sites
Quote:
Original post by Glak
Seriously, why aren't you using std::vector?

It is:

easier
faster (really, these guys write containers for a living, you don't)
easier to get help on, that is if you need help
feature complete (or at least much closer than whatever you are making)

the downside: you'll have to swallow your pride and maybe get used to some of the function names being different from what you would have named them.


Learning exercise? Plus I'm a control freak! :P

Share this post


Link to post
Share on other sites
Quote:
Original post by Raeldor
Learning exercise?

That's valid. Once you've learned how to implement a dynamic array, though, throw it out and use std::vector.
Quote:
Plus I'm a control freak! :P

If you're a control freak, you'll enjoy the fact that std::vector is guaranteed bug-free, gives you a huge amount of customizability by exposing its allocation interface, and works well with the rest of the standard library. If, on the other hand, you are a masochist, you should use a custom-written dynamic array class, because it'll force you to worry about whether it's buggy every time you run into an unknown bug that is at all related to its use. Yow!

Share this post


Link to post
Share on other sites
Yeah... nice memory leak :P ... Just coded it up, but I'm a bit too tired to be coding now. Have been using garbage collection for too long :P. As I said.. I dropped it for std::vector.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
if you are creating an array of auto_ptr.

For auto_ptr, copies are NOT equivalent.

It turns out that this has important effects when you try to use auto_ptrs with generic code that does make copies and isn't necessarily aware that copies aren't equivalent (after all, usually copies are!). Consider the following code that I regularly see posted on the C++ newsgroups:

// Example 8: Danger, Will Robinson!
//
vector > v;

/* ... */

sort( v.begin(), v.end() );

It is never safe to put auto_ptrs into standard containers. Some people will tell you that their compiler and library compiles this fine, and others will tell you that they've seen exactly this example recommended in the documentation of a certain popular compiler; don't listen to them.

The problem is that auto_ptr does not quite meet the requirements of a type you can put into containers, because copies of auto_ptrs are not equivalent. For one thing, there's nothing that says a vector can't just decide to up and make an "extra" internal copy of some object it contains. For another, when you call generic functions that will copy elements, like sort() does, the functions have to be able to assume that copies are going to be equivalent. At least one popular sort internally takes a copy of a "pivot" element, and if you try to make it work on auto_ptrs it will merrily take a copy of the pivot auto_ptr object (thereby taking ownership and putting it in a temporary auto_ptr on the side), do the rest of its work on the sequence (including taking further copies of the now-non-owning auto_ptr that was picked as a pivot value), and when the sort is over the pivot is destroyed and you have a problem: At least one auto_ptr in the sequence (the one that was the pivot value) no longer owns the pointer it once held, and in fact the pointer it held has already been deleted!

So the standards committee bent over backwards to do everything it could to help you out: The Standard auto_ptr was deliberately and specifically designed to break if you try to use it with the standard containers (or, at least, to break with most natural implementations of the standard library). To do this, the committee used a trick: auto_ptr's copy constructor and copy assignment operator take references to non-const to the right-hand-side object. The standard containers' single-element insert() functions take a reference to const, and hence won't work with auto_ptrs.

here is the full article:
http://www.gotw.ca/publications/using_auto_ptr_effectively.htm

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
// Example 8: Danger, Will Robinson!
//
vector > v;

/* ... */

sort( v.begin(), v.end() );

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
arg....the code wont show up right


Post it between '[s o u r ce]' and '[/ s o u r ce]' tags. (without the spaces between letters!!)

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