smart pointers and arrays - c++

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.

Related

delete a variable out of scope

int* func()
{
int* i=new int[1];
//do something
return i;
}
void funcc()
{
int* tmp=func();
//delete allocated memory after use
delete tmp;
}
should delete working as described in the second function be a correct use ?
I think I didn't allocate memory to it by new ? new was used in the first, to be sure.
It should be delete [] tmp; because you're doing array new, but otherwise, it's correct.
As others have stated, you should use delete[] to delete arrays, not delete.
But, if you're asking whether it's okay to delete tmp because the memory it points to wasn't allocated with new, then your premise is incorrect.
It was allocated with new. The address of the memory that you allocate within the function for i is passed back to be stored in tmp, so it does point to memory that was allocated by new.
You're correct that i itself is out of scope at that point but memory allocated by new survives the scope change on exit from the function. And, since you're storing its location into tmp, you still have access to it.
Hence the deletion (once you make it an array deletion with []) is quite valid.
This is Undefined Behaviourâ„¢. You can only use delete if you used new. If you used new[], you MUST delete[] it. More than that, this is hideously unsafe code- you need a smart pointer.
No. new T[] should match delete []t. And new T should match delete t. Otherwise, your code would invoke undefined bevavior.
And it doesn't matter if you do delete []tmp outside the function. Its okay to do so. All that you need to keep in mind that the form of delete.
My spidey-senses tell me that you're wondering whether the dynamically-allocated int that you create in func is the same one that you attempt to delete in funcc.
The answer is: yes. Although you don't use strictly the same pointer variable, both pointers point to the same object.
However, please remember to use delete[] (with the []) when you used new[] (with the []). Your code is broken until you fix this.
Also, try to avoid newing in one place and deleteing in another. Perhaps consider a std::vector instead, which is far less error-prone.

Questions about a array of pointers in c++

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.

Why is there a delete[] in C++?

Why is there a delete[]? From my understanding its to behave differently for arrays. However, why does it really exist? There's only free in C and no free_array. Also in syntax the only difference between delete var and delete []var is the [] which has no params (I'm not telling the length of the array).
So why does delete[] really exist? I know someone will say you can overload delete and delete[] (at least i think that is possible) but lets say we are not overloading it. Why does it exist?
Typically, for non-POD classes, a delete[] expression must call destructors on a variable number of class instances that cannot be determined at compile time. The compiler typically has to implement some run time "magic" that can be used to determine the correct number of objects to destroy.
A delete expression doesn't have to worry about this, it simply has to destroy the one object that the supplied pointer is pointing to. Because of this, it can have a more efficient implementation.
By splitting up delete and delete[], delete can be implemented without the overhead needed to correctly implement delete[] as well.
If you delete an array, only first object's destructor will be called. delete[] calls destructors of all objects in array and frees array's memory.
Assume delete[] didn't exist, write the code for deleting the array vs deleting only the first element in the array.
delete array; // Deletes first element, oops
delete &array; // Deletes first element, oops
delete &array[0]; // Deletes first element
A pointer to an array being an alias for a pointer to the first element of the array is of course an old C "feature".
Consider:
int* a = new int[25];
int* b = a;
delete b; // only deletes the first element
The C++ compiler has no idea whether b points to an array or a single element. Calling delete on an array will only delete the first element.

Can you use a shared_ptr for RAII of C-style arrays?

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.

C++ deleting a pointer to a pointer

So I have a pointer to an array of pointers. If I delete it like this:
delete [] PointerToPointers;
Will that delete all the pointed to pointers as well? If not, do I have to loop over all of the pointers and delete them as well, or is there an easier way to do it? My google-fu doesn't seem to give me any good answers to this question.
(And yeah, I know I need to use a vector. This is one of those "catch up on C++" type assignments in school.)
Yes you have to loop over the pointers, deleting individually.
Reason: What if other code had pointers to the objects in your array? The C++ compiler doesn't know if that's true or not, so you have to be explicit.
For an "easier way," two suggestions: (1) Make a subroutine for this purpose so at least you won't have to write the code more than once. (2) Use the "smart pointer" design paradigm where you hold an array of objects with reference-counters, then the objects are deleted when the objects are no longer referenced by any code.
I agree with Jason Cohen though we can be a bit clearer on the reason for needing to delete your pointers with the loop. For every "new" or dynamic memory allocation there needs to be a "delete" a memory de-allocation. Some times the "delete" can be hidden, as with smartpointers but it is still there.
int main()
{
int *pI = new int;
int *pArr = new int[10];
so far in the code we have allocated two chunks of dynamic memory. The first is just a general int the second is an array of ints.
delete pI;
delete [] pArr;
these delete statements clear the memory that was allocated by the "new"s
int ppArr = new int *[10];
for( int indx = 0; indx < 10; ++indx )
{
ppArr[indx] = new int;
}
This bit of code is doing both of the previous allocations. First we are creating space for our int in a dynamic array. We then need to loop through and allocate an int for each spot in the array.
for( int indx = 0; indx < 10; ++indx )
{
delete ppArr[indx];
}
delete [] ppArr;
Note the order that I allocated this memory and then that I de-allocated it in the reverse order. This is because if we were to do the delete [] ppArr; first we would lose the array that tells us what our other pointers are. That chunk or memory would be given back to the system and so can no longer be reliably read.
int a=0;
int b=1;
int c=2;
ppArr = new int *[3];
ppArr[0] = &a;
ppArr[1] = &b;
ppArr[2] = &c;
This I think should be mentioned as well. Just because you are working with pointers does not mean that the memory those pointers point to was dynamically allocated. That is to say just because you have a pointer doesn't mean it necessarily needs to be delete. The array I created here is dynamically allocated but the pointers point to local instances of ints When we delete this we only need to delete the array.
delete [] ppArr;
return 0;
}
In the end dynamically allocated memory can be tricky and anyway you can wrap it up safely like in a smart pointer or by using stl containers rather then your own can make your life much more pleasant.
See boost pointer container for a container that does the automatic deletion of contained pointers for you, while maintaining a syntax very close to ordinary STL containers.
Pointers are pretty much just memory references and not spiffy little self-cleaning .net objects. Creating proper destructors for each class will make the deletion a little cleaner than massive loops throughout the code.
Let's take a (pseudocoded) real world example .Imagine that you had a class like this:
class Street
{
public:
Street();
~Street();
private:
int HouseNumbers_[];
}
typedef *Street StreetSign;
If you have an array of street signs, and you delete your array of streetsigns, that doesn't mean that you automatically delete the sreets. They re still there, bricks and mortar, they just don't have those signs pointing to them any more. You have got rid of those specific instances of pointers to the streets.
An array of pointers is (conceptually) a bit like an array of integers, it's an array of numbers representing the memory locations of various objects. It isn't the objects themselves.
If you delete[] the array of pointers, all you have done is delete an array of integers.
I think you're going to have to loop over I'm afraid.
I don't know why this was answered so confusingly long.
If you delete the array of pointers, you will free
the memory used for an array of usually ints.
a pointer to an object is an integer containing the adress.
You deleted a bunch of adresses, but no objects.
delete does not care about the content of a memory space,
it calls a destructor(s) and marks the mem as free.
It does not care that it just deleted a bunch of adresses
of objects, it merely sees ints.
That's why you have to cycle through the array first! and call delete
on every element, then you can delete the storage of the array itself.
Well, now my answer got somewhat long... .... strange... ;)
Edit:
Jason's answer is not wrong, it just fails to hit the spot. Neither
the compiler nor anything else in c(++) cares about you deleting stuff that is elsewhere
pointed to. You can just do it. Other program parts trying to use the deleted objects
will segfault on you. But no one will hinder you.
Neither will it be a problem to destroy an array of pointers to objects, when the objects
are referenced elsewhere.