shared_ptr<void> t(new char[num])
means memory leak?
If so, what is the correct practice in this case.
should I use shared_array<> instead?
I'm editing the bytes pointed by 't' manually for later transfer in a TCP Stream.
means memory leak?
No, it means undefined behavior. (Which could have any symptom, including memory leak.) The call to delete must match the call to new. Yours doesn't. You allocate with new[] but destroy with delete.
If so, what is the correct practice in this case. Should I use shared_array<> instead?
There are two easy choices. You can use shared_array:
shared_array<char> t(new char[num])
t[7] = 42;
Or, you could use a shared_ptr to a std::vector:
shared_ptr<std::vector<char> > t(new std::vector<char>(num))
(*t)[7] = 42;
EDIT: Thanks to #Dennis Zickefoose for gently pointing out an error in my thinking. Parts of my answer are rewritten.
As I see the void You mention in the Q is a typo, Since Calling delete on a void * is guaranteed Undefined Behavior by the Standard.
For another data type,
You will have to provide your custom deletor to the shared_ptr so you can call delete [].
Eg:
For example:
template<typename T>
struct Customdeleter
{
void operator()(T* p)
{
delete [] p;
}
};
And invoke as:
shared_ptr<char> sp(new char[num], Customdeleter<char>());
EDIT:
Since you clarified are using Boost in comments and not TR1(AFAIK TR1 doesn't have shared_array)
You can use shared_array:
shared_array<char> sp(new char[num])
I think I see where you're coming from - you want void * pointers so you can later cast it to the final type you're serializing. But as others have pointed out, you can't delete a void* pointer, and neither can the code for shared_ptr.
Since you're allocating an array of char, that should be the type of smart pointer you use:
shared_array<char> t(new char[num]);
Casting the raw char pointer to another type shouldn't be any more of a problem than casting a void* pointer.
You're calling delete on void* which is undefined behavior.
the reason I'm using a void* is because I'm allocating 'num' bytes for storage of different types of variables, like the first 4 bytes represent a double, next 2 bytes are short..
Use a struct or union then.
I don't know if C++11 has a shared_array, but Boost does — you should use that instead.
Related
Suppose I have the following code:
void* my_alloc (size_t size)
{
return new char [size];
}
void my_free (void* ptr)
{
delete [] ptr;
}
Is this safe? Or must ptr be cast to char* prior to deletion?
Deleting via a void pointer is undefined by the C++ Standard - see section 5.3.5/3:
In the first alternative (delete
object), if the static type of the
operand is different from its dynamic
type, the static type shall be a base
class of the operand’s dynamic type
and the static type shall have a
virtual destructor or the behavior is
undefined. In the second alternative
(delete array) if the dynamic type of
the object to be deleted differs from
its static type, the behavior is
undefined.
And its footnote:
This implies that an object cannot be
deleted using a pointer of type void*
because there are no objects of type
void
.
It depends on "safe." It will usually work because information is stored along with the pointer about the allocation itself, so the deallocator can return it to the right place. In this sense it is "safe" as long as your allocator uses internal boundary tags. (Many do.)
However, as mentioned in other answers, deleting a void pointer will not call destructors, which can be a problem. In that sense, it is not "safe."
There is no good reason to do what you are doing the way you are doing it. If you want to write your own deallocation functions, you can use function templates to generate functions with the correct type. A good reason to do that is to generate pool allocators, which can be extremely efficient for specific types.
As mentioned in other answers, this is undefined behavior in C++. In general it is good to avoid undefined behavior, although the topic itself is complex and filled with conflicting opinions.
It's not a good idea and not something you would do in C++. You are losing your type info for no reason.
Your destructor won't be called on the objects in your array that you are deleting when you call it for non primitive types.
You should instead override new/delete.
Deleting the void* will probably free your memory correctly by chance, but it's wrong because the results are undefined.
If for some reason unknown to me you need to store your pointer in a void* then free it, you should use malloc and free.
Deleting a void pointer is dangerous because destructors will not be called on the value it actually points to. This can result in memory / resource leaks in your application.
If you really must do this, why not cut out the middle man (the new and delete operators) and call the global operator new and operator delete directly? (Of course, if you're trying to instrument the new and delete operators, you actually ought to reimplement operator new and operator delete.)
void* my_alloc (size_t size)
{
return ::operator new(size);
}
void my_free (void* ptr)
{
::operator delete(ptr);
}
Note that unlike malloc(), operator new throws std::bad_alloc on failure (or calls the new_handler if one is registered).
The question makes no sense. Your confusion may be partly due to the sloppy language people often use with delete:
You use delete to destroy an object that was dynamically allocated. Do do so, you form a delete expression with a pointer to that object. You never "delete a pointer". What you really do is "delete an object which is identified by its address".
Now we see why the question makes no sense: A void pointer isn't the "address of an object". It's just an address, without any semantics. It may have come from the address of an actual object, but that information is lost, because it was encoded in the type of the original pointer. The only way to restore an object pointer is to cast the void pointer back to an object pointer (which requires the author to know what the pointer means). void itself is an incomplete type and thus never the type of an object, and a void pointer can never be used to identify an object. (Objects are identified jointly by their type and their address.)
Because char has no special destructor logic. THIS won't work.
class foo
{
~foo() { printf("huzza"); }
}
main()
{
foo * myFoo = new foo();
delete ((void*)foo);
}
The d'ctor won't get called.
A lot of people have already commented saying that no, it's not safe to delete a void pointer. I agree with that, but I also wanted to add that if you're working with void pointers in order to allocate contiguous arrays or something similar, that you can do this with new so that you'll be able to use delete safely (with, ahem, a little of extra work). This is done by allocating a void pointer to the memory region (called an 'arena') and then supplying the pointer to the arena to new. See this section in the C++ FAQ. This is a common approach to implementing memory pools in C++.
If you want to use void*, why don't you use just malloc/free? new/delete is more than just memory managing. Basically, new/delete calls a constructor/destructor and there are more things going on. If you just use built-in types (like char*) and delete them through void*, it would work but still it's not recommended. The bottom line is use malloc/free if you want to use void*. Otherwise, you can use template functions for your convenience.
template<typename T>
T* my_alloc (size_t size)
{
return new T [size];
}
template<typename T>
void my_free (T* ptr)
{
delete [] ptr;
}
int main(void)
{
char* pChar = my_alloc<char>(10);
my_free(pChar);
}
There is hardly a reason to do this.
First of all, if you don't know the type of the data, and all you know is that it's void*, then you really should just be treating that data as a typeless blob of binary data (unsigned char*), and use malloc/free to deal with it. This is required sometimes for things like waveform data and the like, where you need to pass around void* pointers to C apis. That's fine.
If you do know the type of the data (ie it has a ctor/dtor), but for some reason you ended up with a void* pointer (for whatever reason you have) then you really should cast it back to the type you know it to be, and call delete on it.
I have used void*, (aka unknown types) in my framework for while in code reflection and other feats of ambiguity, and so far, I have had no troubles (memory leak, access violations, etc.) from any compilers. Only warnings due to the operation being non-standard.
It perfectly makes sense to delete an unknown (void*). Just make sure the pointer follows these guidelines, or it may stop making sense:
1) The unknown pointer must not point to a type that has a trivial deconstructor, and so when casted as an unknown pointer it should NEVER BE DELETED. Only delete the unknown pointer AFTER casting it back into the ORIGINAL type.
2) Is the instance being referenced as an unknown pointer in stack bound or heap bound memory? If the unknown pointer references an instance on the stack, then it should NEVER BE DELETED!
3) Are you 100% positive the unknown pointer is a valid memory region? No, then it should NEVER BE DELTED!
In all, there is very little direct work that can be done using an unknown (void*) pointer type. However, indirectly, the void* is a great asset for C++ developers to rely on when data ambiguity is required.
If you just want a buffer, use malloc/free.
If you must use new/delete, consider a trivial wrapper class:
template<int size_ > struct size_buffer {
char data_[ size_];
operator void*() { return (void*)&data_; }
};
typedef sized_buffer<100> OpaqueBuffer; // logical description of your sized buffer
OpaqueBuffer* ptr = new OpaqueBuffer();
delete ptr;
For the particular case of char.
char is an intrinsic type that does not have a special destructor. So the leaks arguments is a moot one.
sizeof(char) is usually one so there is no alignment argument either. In the case of rare platform where the sizeof(char) is not one, they allocate memory aligned enough for their char. So the alignment argument is also a moot one.
malloc/free would be faster on this case. But you forfeit std::bad_alloc and have to check the result of malloc. Calling the global new and delete operators might be better as it bypass the middle man.
Consider:
delete new std :: string [2];
delete [] new std :: string;
Everyone knows the first is an error. If the second wasn't an error, we wouldn't need two distinct operators.
Now consider:
std :: unique_ptr <int> x (new int [2]);
std :: unique_ptr <int> y (new int);
Does x know to use delete[] as opposed to delete?
Background: this question floated through my head when I thought array type qualification of pointers would be a handy language feature.
int *[] foo = new int [2]; // OK
int * bar = new int; // OK
delete [] foo; // OK
delete bar; // OK
foo = new int; // Compile error
bar = new int[2]; // Compile error
delete foo; // Compile error
delete [] bar; // Compile error
Unfortunately, they don't know what delete to use therefore they use delete. That's why for each smart pointer we have a smart array counterpart.
std::shared_ptr uses delete
std::shared_array uses delete[]
So, your line
std :: unique_ptr <int> x (new int [2]);
actually causes undefined behavior.
Incidentally, if you write
std :: unique_ptr<int[]> p(new int[2]);
^^
then delete[] will be used since you've explicitly requested that. However, the following line will still be UB.
std :: unique_ptr<int[]> p(new int);
The reason that they can't choose between delete and delete[] is that new int and new int[2] are exactly of the same type - int*.
Here's a related question of using correct deleters in case of smart_ptr<void> and smart_ptr<Base> when Base has no virtual destructor.
There is no "magical" way to detect whether a int* refers to:
a single heap allocated integer
a heap allocated array
an integer in a heap allocated array
The information was lost by the type system and no runtime method (portable) can fix it. It's infuriating and a serious design flaw (*) in C that C++ inherited (for the sake of compatibility, some say).
However, there are some ways of dealing with arrays in smart pointers.
First, your unique_ptr type is incorrect to deal with an array, you should be using:
std::unique_ptr<int[]> p(new int[10]);
which is meant to call delete[]. I know there is talk of implementing a specific warning in Clang to catch obvious mismatches with unique_ptr: it's a quality of implementation issue (the Standard merely says it's UB), and not all cases can be covered without WPA.
Second, a boost::shared_ptr can have a custom deleter which could if you design it to call the correct delete[] operator. However, there is a boost::shared_array especially designed for this. Once again, detection of mismatches is a quality of implementation issue. std::shared_ptr suffers the same issue (edited after ildjarn's remark).
I agree that it's not pretty. It seems so obnoxious that a design flaw (*) from the origins of C haunts us today still.
(*) some will say that C leans heavily toward avoiding overhead and this would have added an overhead. I partly disagree: malloc always know the size of the block, after all.
From Microsoft's documentation:
(A partial specialization unique_ptr<Type[]> manages array objects allocated with new[], and has the default deleter default_delete<Type[]>, specialized to call delete[] _Ptr.)
I added the two final square brackets, seems like a typo as it doesn't make sense without them.
std::unique_ptr is not meant for array as I quote latest boost document:
Normally, a shared_ptr cannot correctly hold a pointer to a
dynamically allocated array. See shared_array for that usage.
If you want to memory management for array of pointer, you have a few options depend on your requirement:
Use boost::shared_array
Use std::vector of boost::shared_ptr
Use boost pointer container like boost::ptr_vector
Nicolai Josuttis ⟶ Note that the default deleter provided by std::shared_ptr calls delete, not delete[]. This means that the default deleter is appropiate only if a shared pointer owns a single object created with new. Unfortunately, creating a std::shared_ptr for an array is possible but wrong:
std::shared_ptr<int>(new int[10]) //error but compiles
So if you use new[] to create an array of objects you have to define your own deleter. For example
std::shared_ptr<int> ptr(new int[10],
[](int* p){ delete[] p; });
or
std::shared_ptr<int> ptr(new int[10],
std::default_delete<int[]>());
For me this is the best solution!
How do smart pointers handle arrays? For example,
void function(void)
{
std::unique_ptr<int> my_array(new int[5]);
}
When my_array goes out of scope and gets destructed, does the entire integer array get re-claimed? Is only the first element of the array reclaimed? Or is there something else going on (such as undefined behavior)?
It will call delete[] and hence the entire array will be reclaimed but I believe you need to indicate that you are using an array form of unique_ptrby:
std::unique_ptr<int[]> my_array(new int[5]);
This is called as Partial Specialization of the unique_ptr.
Edit: This answer was wrong, as explained by the comments below. Here's what I originally said:
I don't think std::unique_ptr knows to call delete[]. It effectively
has an int* as a member -- when you delete an int* it's going to
delete the entire array, so in this case you're fine.
The only purpose of the delete[] as opposed to a normal delete is that
it calls the destructors of each element in the array. For primitive
types it doesn't matter.
I'm leaving it here because I learned something -- hope others will too.
Hi there i have some questions about pointers and arrays in c++:
when i want to pass an array of pointers in a function i must write:
foo(test *ptest[])
right?
when i want to delete a array of pointers, does
delete ptest;
all for me?
when i pass a pointer to another class and the first class make a delete, the pointer is deletete in all classes right?
must i always create a array of a constant size?
First of all, forget about arrays and pointers and tell us what you really want to achieve. You are probably better off using std::vector<T> and pass that around by (const) reference, saving you all the headaches of manual resource management and crazy array-to-pointer-decay rules inherited from C.
Now to answer your questions:
when i want to pass an array of pointers in a function i must write:
foo(test *ptest[])
right?
Yes, but remember that array parameters are always rewritten by the compiler to pointers. Your code is equivalent to:
foo(test **ptest)
This means that all information about the size of the array has been lost. Moving on:
when i want to delete a array of pointers, does
delete ptest;
all for me?
No. If you acquire via new[], you must release via delete[], otherwise you get undefined behavior. Note that deleting an array of pointers only gets rid of the array itself, not any objects pointed to by the pointers stored inside the array.
Again: Forget about arrays and pointers and use the facilities provided by the C++ standard library.
when i want to delete a array of pointers, does delete ptest; all for me?
Nope. It tries to delete what's been allocated to the address ptest. If ptest is not something which was allocated dynamically, your program will crash. You can only call delete on the addresses which you have received from new.
when i pass a pointer to another class and the first class make a delete, the pointer is deletete in all classes right?
Nope, you need to have exactly one delete for every new. (yah, there are "smart pointers" which call delete for you, but the point still holds.)
must i always create a array of a constant size?
Nope. In C++ there's std::vector for having arrays of dynamic size (can be used for constant-size arrays too) and in C there's realloc for changing a size of an array.
To delete any array you need:
delete [] ptest; // note the [] part
Arrays can be any size you like (within various practical limits) and unless you make copies of an array then you should delete it exactly once (it doesn't matter where you do this, so long as you don't try to acess the data afterwards).
Chances are, without knowing what you're aiming at and any other contextual information, you should use std::vector<T> instead and forget about these worries.
That said, to delete any primitive array arr you must say
delete[] arr;
Of course, if the pointers in the array themselves are each the last pointing at heap memory then you should free them first. You can do that nicely with a reusable Delete functor:
struct Delete {
template<class P>
void operator()(P ptr) const { delete ptr; }
};
// ...
std::foreach(arr, arr+ARR_LENGTH, Delete());
delete[] arr;
You must of course make sure no two pointers point at the same address. To further simplify things beyond what a std::vector<T> can do for you you should consider using a boost::shared_ptr<T>; this will allow you to forget about the delicate case in which two pointers point at the same address.
I'm working on a section of code that has many possible failure points which cause it to exit the function early. The libraries I'm interacting with require that C-style arrays be passed to the functions. So, instead of calling delete on the arrays at every exit point, I'm doing this:
void SomeFunction(int arrayLength)
{
shared_ptr<char> raiiArray(new char[arrayLength]);
pArray = raiiArray.get();
if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }
//etc.
}
I wanted to use unique_ptr, but my current compiler doesn't support it and the reference count overhead doesn't really matter in this case.
I'm just wondering if anyone has any thoughts on this practice when interfacing with legacy code.
UPDATE I completely forgot about the shared_ptr calling delete instead of delete []. I just saw no memory leaks and decided to go with it. Didn't even think to use a vector. Since I've been delving into new (for me) C++ lately I'm thinking I've got a case of the "If the only tool you have is a hammer, everything looks like a nail." syndrome. Thanks for the feedback.
UPDATE2 I figured I'd change the question and provide an answer to make it a little more valuable to someone making the same mistake I did. Although there are alternatives like scoped_array, shared_array and vector, you can use a shared_ptr to manage scope of an array (but after this I have no idea why I would want to):
template <typename T>
class ArrayDeleter
{
public:
void operator () (T* d) const
{
delete [] d;
}
};
void SomeFunction(int arrayLength)
{
shared_ptr<char> raiiArray(new char[arrayLength], ArrayDeleter<char>());
pArray = raiiArray.get();
if(SomeFunctionThatRequiresCArray(pArray) == FAILED) { return; }
//etc.
}
Do not use shared_ptr or scoped_ptr to hold pointers to dynamically allocated arrays. shared_ptr and scoped_ptr use delete ptr; to clean-up when the pointer is no longer referenced/goes out of scope, which invoked undefined behaviour on a dynamically allocated array. Instead, use shared_array or scoped_array, which correctly use delete[] ptr; when destructing.
To answer your question, if you are not going to pass the smart pointer around, use scoped_array, as it has less overhead than shared_array.
Alternatively, use std::vector as the array storage (vectors have guaranteed contiguous memory allocation).
Use boost::scoped_array, or even better std::vector if you are dealing with an array.
I highly recommend simply using a std::vector. Elements in vectors are allocated on the heap, and will be deleted when the vector goes out of scope, wherever you exit the function.
In order to pass a vector to legacy code requiring C-style arrays, simply pass &vectorName[0]. The elements are guaranteed to be contiguous in memory.
Some remarks for C++11 users:
For shared_ptr, there is in C++11 a default deleter for array types defined in <memory> and standard compliant (wrt the final draft) so it can be used without additional fancy deleters for such cases:
std::shared_ptr<char> raiiArray(new char[arrayLength], std::default_delete<char[]>());
unique_ptr in C++11 has a partial specialization to deal with new[] and delete[]. But it does not have a shared behavior, unfortunately. Must be a good reason there is no such specialization for shared_ptr but I didn't look for it, if you know it, please share it.
There's boost::scoped_ptr for this.
This
shared_ptr<char*> raiiArray(new char[arrayLength]);
is not a good practice, but causes undefined behaviour, as you allocate with operator new[], but shared_ptr uses operator delete to free the memory. The right thing to use is boost::shared_array or add a custom deleter.