tags:

views:

193

answers:

4

I'd need a class like std::auto_ptr for an array of unsigned char*, allocated with new[]. But auto_ptr only calls delete and not delete[], so i can't use it.

I also need to have a function which creates and returns the array. I came out with my own implementation within a class ArrayDeleter, which i use like in this example:

#include <Utils/ArrayDeleter.hxx>

typedef Utils::ArrayDeleter<unsigned char> Bytes;

void f()
{
  // Create array with new
  unsigned char* xBytes = new unsigned char[10];
  // pass array to constructor of ArrayDeleter and
  // wrap it into auto_ptr
  return std::auto_ptr<Bytes>(new Bytes(xBytes));
}

...
// usage of return value
{
  auto_ptr<Bytes> xBytes(f());
}// unsigned char* is destroyed with delete[] in destructor of ArrayDeleter

Is there a more elegant way to solve this? (Even using another "popular" library)

+10  A: 

Boost has a variety of auto-pointers, including ones for arrays. Have you considered if std::vector is sufficient? Vectors are guaranteed to be contiguous in memory, and if you know the size and allocated memory ahead of time the location in memory will not change.

John Gordon
I had a look at boost and I think the scoped_array would do it. Thanks
Gianluca
@Gianluca: Why won't you use vector?
GMan
@GMan: sure, now i see it's a much better idea. Thanks
Gianluca
+2  A: 

How about using std::basic_string<unsigned char>? Or maybe std::vector<unsigned char>?

Thomas
I then have to call a methods that takes unsigned char* as argument. Is there a way to access it from inside one of the containers you suggest? Will basic_string's method data() do it?
Gianluca
You could use the std::string '.c_str()' method, this returns a null terminated char* .
Konrad
+3  A: 

I then have to call a methods that takes unsigned char* as argument.

std::vector<unsigned char> vec;
.
.
.
legacy_function(&vec[0], vec.size());
FredOverflow
perfect, thanks
Gianluca
A: 
  1. You're talking about an array of int, not complex C++ types that have a destructor. For such an array calling delete[] is equivalent to calling delete. So there's no problem to use std::auto_ptr.

  2. The method you suggest is very barbaric IMHO. You actually allocate memory twice: once for the needed array, and then you also allocate an instance of ArrayDeleter, which encapsulates the pointer to the allocated array.

The drawbacks of such a method are:

  • Worse performance. Heap operations are heavy. Also they have significant memory overhead.
  • Slower access. To access an element of your array via the std::auto_ptr<Bytes> the compiler will generate two indirections: one to get your Bytes object, and the other to access the element. In simple words: std::auto_ptr has a pointer to Bytes object, which has a pointer to the array.
  • Worse error/exception consistency. Imagine what if the operator new fails to allocate the Bytes object. It'll generate an exception, which may be handled. But at this point you've already allocated the array. And this allocation will be lost.

I'd do one of the following:

  1. If you're talking about an ordinary type - just use std::auto_ptr<type>. This should do the work. However you should check it with your compiler.

  2. For complex types: you may create your own wrapper instead of the std::auto_ptr.

  3. Another variant: similar to what you did. However you should get rid of the extra memory allocations and indirections.
valdo
Calling `delete` on a dynamically allocated array is ALWAYS UNDEFINED BEHAVIOR, even if it always seemed to work for you on all the compilers you tried.
FredOverflow
Francesco
This is exactly the reason why I've written "you should check it with your compiler."Strictly speaking you're right. The standard says it's an undefined behavior. OTOH I said what *actually* happens. At least on MSVC compiler.The reason why "delete[]" should be used instead of "delete" is not because we need to know how much memory should be freed - according this argument you'd have to pass the memory size into "free" function as well.The reason is that when you used "delete[]" the compiler generates calls to d'tors of objects in addition to freeing the memory.
valdo
@valdo: But people want to program C++, not a specific variant of it. Relying on undefined behavior is bad.
GMan
@Valdo that's not true: when you use delete[] you deallocate the right amount of memory in the right form. Why do you suggest to rely on the eccentric behaviour of (some version of) a compiler, I don't know.
Francesco