Hi, I just implemented my first resizable container ( std::vector ) and it broke on the first attempt lol!
Heap corruption is caught when the assignment operator attempts to free() old data, and it works fine without free() , which of course is a leak.
Here's the use case : ( simplified from a recursive function )
typedef struct Widget
{
Vec3 pos;
float width;
float height;
List<Widget> children;
};
List<Widget> list ;
Widget widget = {};
widget.children.add (widget);
widget.children.add (widget); // Heap corruption when free() is called in assignment operator=()
Definition :
template <typename T>
struct List
{
T* start = 0;
u64 capacity = 0;
u64 size = 0;
inline List ( ) {};
inline List ( u32 count );
inline List ( const List<T>& other ) ;
inline ~List ( );
inline void add ( T element );
inline void reserve ( u32 count );
inline void clear ();
inline T& operator[] (u64 x)
{
return start[x];
}
inline List<T>& operator=( List<T>& other );
};
template <typename T>
List<T>::List ( u32 count )
{
u32 len = sizeof(T) * count;
start = (T*) malloc ( len );
size = 0;
capacity = len;
};
template <typename T>
List<T>::List ( const List<T>& other )
{
u64 len = other.size * sizeof(T) ;
if ( other.size )
{
start = (T*) malloc ( len );
for ( int i=0; i < other.size; i++)
{
start[i] = other.start[i];
}
}
size = other.size;
capacity = len;
}
template <typename T>
List<T>::~List ( )
{
if ( start )
free ( start );
};
template <typename T>
List<T>& List<T>::operator=( List<T>& other )
{
u64 len = other.size * sizeof(T) ;
if ( other.size )
{
if ( start )
free ( start ); // Corruption exception from here
start = (T*) malloc ( len );
for ( int i=0; i < other.size; i++)
{
start[i] = other[i];
}
}
size = other.size;
capacity = len;
return *this;
}
template <typename T>
inline void List<T>::add ( T element )
{
if ( !start )
{
reserve ( 1 );
start[size] = element;
size++;
return;
}
if ( size >= ( capacity / sizeof(T) ) )
{
reserve ( size + 1 );
}
start[size] = element;
size++;
};
template <typename T>
inline void List<T>::reserve ( u32 count )
{
if ( count == 0 )
{
clear();
return;
}
if ( count == size )
{
return;
}
T* old = start;
u64 len = sizeof(T) * count * 2;
start = (T*) malloc ( len );
for ( int i=0; i < size; i++)
{
start[i] = old[i];
}
capacity = len;
if ( old )
free ( old );
}
template <typename T>
inline void List<T>::clear ()
{
if ( start )
free ( start );
size = 0;
capacity = 0;
};
For some reason it sometimes works without any exceptions being thrown..