3

This is possibly a candidate for a one-line answer. I would like know it anyway..

I am writing a simple circular buffer and for some reasons that are not important for the question I need to implement it using an array of doubles. In fact I have not investiated other ways to do it, but since an array is required anyway I have not spent much time on looking for alternatives.

template<typename T>
class CircularBuffer
{
public:
    CircularBuffer(unsigned int size);
    ~CircularBuffer();
    void Resize(unsigned int new_size);
    ...
private:
    T* buffer;
    unsigned int buffer_size;
};

Since I need to have the buffer dynamically sized the buffer_size is neither const nor a template parameter. Now the question:

During construction and in function Resize(int) I only require the size to be at least one, although a buffer of size one is effectively no longer a buffer. Of course using a simple double instead would be more appropriate but anyway.

Now when deleting the internal buffer in the destructor - or in function resize for that matter - I need to delete the allocated memory. Question is, how? First candidate is of course delete[] buffer; but then again, if I have allocated a buffer of size one, that is if the pointer was aquired with buffer = new T[0], is it still appropriate to call delete[] on the pointer or do I need to call delete buffer; (without brackets) ?

Thanks, Arne

Arne
  • 1,111
  • 2
  • 11
  • 22
  • Actually I've always wondered why C++ doesn't define `new T`; as `new T[1];` as it would simplify the deletion. My only guess is that it is for optimization reasons (the compiler wouldn't have to create a one-step loop when calling the destructor). – Viktor Sehr Jun 07 '10 at 11:33
  • 1
    @Victor Sehr: Doing so would restrict the user to parameterless constructors for type T. – sharptooth Jun 07 '10 at 11:36
  • It would make the deletion more complex, as you would have to use delete []. –  Jun 07 '10 at 11:36
  • @sharptooth: what do you mean? @Neil Butterworth: If anything, it would make deletion more simple as only one form of delete is needed. – Viktor Sehr Jun 07 '10 at 12:29
  • @Viktor Sehr: Using `new[]` requires that type has a default constructor. Implementing `new` through `new[]` would enforce that requirement on all classes you use `new` on. – sharptooth Jun 07 '10 at 12:35
  • @sharptooth: you could still create it as `T val = new T(arg0...);`, and the compiler allocates with something like malloc(sizeof(T)) and runs the placement new on the adress. This only regard the destructor, and the compiler could handle the destruction of a `new T` as it would handle a `new T[1];` – Viktor Sehr Jun 07 '10 at 12:40
  • @Viktor Sehr: Don't you see how much fine print is in such design? – sharptooth Jun 07 '10 at 12:55
  • To but it simply: why doesn't C++ implement the deletion/destruction of an object allocated as `new T;`, as it would handle deletion\destruction as an object allocated as `new T[1];` ? – Viktor Sehr Jun 07 '10 at 13:13
  • @Viktor Sehr: This answer might be helpful: http://stackoverflow.com/questions/2499895/whats-the-purpose-of-having-a-separate-operator-new/2500544#2500544 – sharptooth Jun 07 '10 at 13:17

5 Answers5

10

If you allocate the memory with new T[x], you always delete it with delete[], even if x ≤ 1.

kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
7

Why not use a vector?

obelix
  • 986
  • 8
  • 14
  • 1
    +1 That's the most sensible answer to all such questions: Simply avoid manual memory management altogether. What does it buy you over a `std::vector`? – sbi Jun 07 '10 at 11:47
  • Well, as I said I do *need* to use an array. This is because I need to integrate with some code that uses pointers to certain elements for monitoring and I need to guarantee that for example the most recent elment stays at the same memory address during the lifetime of the CircularBuffer object. – Arne Jun 07 '10 at 12:11
  • 1
    @Arne: you have that guarantee if you don't change your vector. You also don't have that guarantee if you reallocate your array. – stefaanv Jun 07 '10 at 12:33
  • @stefaanv I just realized that issue myself, but thanks anyway. – Arne Jun 07 '10 at 12:49
  • this would be more helpful as a comment. It's a perfectly good suggestion, but it doesn't answer his question – jalf Jun 07 '10 at 13:05
  • It actually does answer his question, as std::vector must _contain_ an array. (contiguous element requirement). – MSalters Jun 07 '10 at 13:09
5

Only use delete[] on addresses returned by new[] - regardless of the buffer size. Using delete in this case is undefined behavior.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
1

buffer of size 1 should be allocated as buffer = new T[1] and then delete[] buffer should be used. No need to differentiate as n =1 as special case. Thumb rule :: every new [] should have corresponding delete []

aJ.
  • 34,624
  • 22
  • 86
  • 128
0

When you use "delete[]" it knows that it must delete an array of objects - it calls each destructor of the objects in the array. Do not slip away from the standard - it will only give you a lot of headaches. When using new use delete. When using new [] use delete []. Just as simple as that.

INS
  • 10,594
  • 7
  • 58
  • 89