I am re-working an old circular buffer class i wrote to be more robust. I am allocating a buffer on the heap that is of type T (so the class is templated). However I am having issues with freeing resources that could be possible with T being a pointer to dynamically allocated space.
Here is a ctor with default value parameter in short
template <typename T, unsigned int SIZE>
CircularBuffer(const T default_val) {
_buffer = new T[SIZE];
// assign each block default value, etc
}
// dtor
~CircularBuffer()
{
delete [] _buffer;
}
however, say for example someone decides to do this:
CircularBuffer<int*, 4> cb(new int); // buffer of 4, holding int*, with default value of new int
// later ~CircularBuffer call is made
// user allocated memory is not freed
How would I be able to (or let the user) free this memory? I have tried manually from the user perspective:
delete cb.at(0); // .at returns T& (so it would effectively return the pointer)
// above is access violation
I tried to figure out how to do this in the destructor, but I wasnt able to do any sort of delete _buffer[i] since the compiler thinks that template T is not a pointer (even though it could be).
Can I safely handle this situation, or is there something the user can do about this so that the responsibility is not mine (since the class is not internally allocating this, the user is)?
Edit*** I just realized that the allocation with new when passing a T* as template parameter does not return the buffer size expected.
// call default ctor
CircularBuffer<double*, 2> cb(); // _buffer = new T[SIZE];
// sizeof(_buffer) == 4;
// sizeof(double*) == 4;
// sizeof(double*[2]) == 8; // _buffer should be this size, as it holds 2 4byte pointers, what happened?
Im not sure if I should make a new question for this, or leave it here with the original question, but I think this explains some access violations I was getting before (after trying to dereference _buffer[1] of the above instance. Unfortunately Im not sure what is causing this.
template<typename T>
struct is_pointer{
static const bool value = false;
};
template<typename T>
struct is_pointer<T*>{
static const bool value = true;
};
template <bool, class T = void>
struct enable_if
{};
template <class T>
struct enable_if<true, T>
{
typedef T type;
};
template <bool, class T = void>
struct disable_if
{};
template <class T>
struct disable_if<false, T>
{
typedef T type;
};
template <typename T, unsigned int SIZE>
class CircularBuffer
{
public:
CircularBuffer(){
_buffer = new T[SIZE];
}
~CircularBuffer()
{
free_helper<T,SIZE>();
delete [] _buffer;
}
private:
template<class U, unsigned int SIZE>
void free_helper( typename enable_if< is_pointer<U>::value >::type *dummy=0 ){
//pointer container
for(int i=0;i<SIZE;++i){
//delete it?
U t = _buffer[i];
}
}
template<class U, unsigned int SIZE>
void free_helper( typename disable_if< is_pointer<U>::value >::type *dummy=0 ){
//none pointer container
}
T* _buffer;
};
void main(){
CircularBuffer<int,10> cb;
CircularBuffer<int*,10> cb2;
}