#include <iostream>
class A {
public:
A(int d) : y(d) {}
int y;
};
int main(void) {
A d[3] = {A(0), A(1), A(2)};
std::cout << d[1].y << std::endl;
};
I'm working on a project for university. I'm instructed not to use an object array and instantiate each element with a temporary object of my class - so something like the above code is a no-no. Instead, it's recommended we use a an array of type A* and then use new on each element so that we create an object and make each element point to it.
So we'd have something like this:
A* d[3];
for (int i=0;i<3;i++)
d[i]=new A(i);
However, I don't quite understand the difference in practice when compared to the first version. As far as I understand in the first version we we create the three temporary objects (which are rvalues) using the constructor and then assign them to the array. After the assignment ends, the temporary is destroyed and its values are copied to the array. In the second version, we have the advantage of being able to delete what d[] points to but disregarding that, what is the drawback of using the first method?
EDIT:
class B{
public:
A a1[3];
}
Assuming my initial definition is followed by this (A isn't default constructible, is something like this impossible? So in that case I can't an array of objects and I instead have to resort to a pointer array of type A* and then use new, as my only resort.
Array of pointers -> memory allocation when you create an object and assign it to the pointer. Array of 1000 pointers with 1 element inside = 1x the memory.
Array of objects -> memory allocation when you create an array. Array of 1000 with 1 element inside = 1000x the memory.
1 ) A d[3], it creates a built-in array (or C-style, plain, naked array...) which contains (three) elements of type A, these elements live on the stack (according to your code).
2 ) A* d[3];, it creates a built-in array which contains (three) pointers to elements of type A (or they should). It doesn't mean that the pointed element is of type A, it's developer's task to create those elements, and you can do it in two ways, using the stack (as before):
A element;
...
d[0] = &element;
or using the heap (with new/new[] and delete/delete[]):
d[0] = new A;
...
delete d[0];
Side effects of the second option; you may point to an already destroyed element (i.e. the element is out of scope), hence potential seg fault; you may loose the pointer to the allocated memory (i.e. the array of pointers is out of scope and the allocated memory has not been released), hence memory leak.
However, an advantage is that you can use lazy initialisation (you don't pay for what you don't use). If you don't need an A object in d[2] (or pointed by), why should you create it and waste memory? And here smart pointers arise, they make your life easier allowing you to allocate memory only when you need it, reducing the risk of seg faults (worth it to mention std::weak_ptr), memory leaks, etc:
std::unique_ptr<A> d[3];
d[0] = std::make_unique<A>(); // Call make_unique when you need it
But still a bit nasty, the built-in arrays are good but may be much better under some circumstances. It is hard to add or remove elements, iterate, get the size, access to the tail/head, etc... And that's why containers are quite useful, i.e. std::array or std::vector (where its size doesn't have to be known at compilation time):
std::vector<std::unique_ptr< A> > d(3);
std::array<std::unique_ptr<A,3> > d;
There are no advantages whatsoever to the following code in C++:
A* d[3];
for (int i=0;i<3;i++)
d[i]=new A(i);
In fact, you shouldn't write it at all.
Your solution with a locally-declared temporary array is valid, but has the significant limitation of requiring that the number of elements in the array be a compile-time constant (i.e., known ahead of time).
If you need to have an array with a dynamic number of elements, known only at run time, then you should use a std::vector, which performs the new allocation automatically. That is the idiomatic way of working with dynamically-allocated arrays in C++.
Related
This question is similar to Problem with delete[], how to partially delete the memory?
I understand that deleting an array after incrementing its pointer is not possible as it loses the track of how many bytes to clean. But, I am not able to understand why one-by-one delete/deallocation of a dynamic array doesn't work either.
int main()
{
int n = 5;
int *p = new int[n];
for(int i=0;i<n;++i){
delete &p[i];
}
}
I believe this should work, but in clang 12.0 it fails with the invalid pointer error. Can anyone explain why?
An array is a contiguous object in memory of a specific size. It is one object where you can place your data in and therefore you can only free/delete it as one object.
You are thinking that an array is a list of multiple objects, but that's not true. That would be true for something like a linked list, where you allocate individual objects and link them together.
You allocated one object of the type int[n] (one extent of memory for an array) using the operator new
int *p = new int[n];
Elements of the array were not allocated dynamically separately.
So to delete it you just need to write
delete []p;
If for example you allocated an array of pointers like
int **p = new int *[n];
and then for each pointer of the array you allocated an object of the type int like
for ( int i = 0;i < n;++i )
{
p[i] = new int( i );
}
then to delete all the allocated objects you need to write
for ( int i = 0; i < n; ++i )
{
delete p[i];
}
delete []p;
That is the number of calling of the operator delete or delete [] one to one corresponds to the number of calling operator new or new [].
One new always goes with one delete. Just as that.
In detail, when we request an array using new, what we actually do is to get a pointer that controls a contiguous & fixed block on the memory. Whatever we do with that array, we do it through that pointer and this pointer associates strictly with the array itself.
Furthermore, let's assume that you were able to delete an elemnent in the middle of that array. After the deletion, that array would fall apart and they are not contiguous anymore! By then, an array would not really be an array!
Because of that, we can not 'chop off' an array into separate pieces. We must always treat an array as one thing, not distinctive elements scattered around the memory.
Greatly simplyfyinh: in most systems memory is allocated in logical blocks which are described by the starting pointer of the allocated block.
So if you allocate an array:
int* array = new int[100];
OS stores the information of that allocation as a pair (simplifying) (block_begin, size) -> (value of array ptr, 100)
Thus when you deallocate the memory you don't need to specify how much memory you allocated i.e:
// you use
delete[] array; // won't go into detail why you do delete[] instead of delete - mostly it is due to C++ way of handling destruction of objects
// instead of
delete[100] array;
In fact in bare C you would do this with:
int* array = malloc(100 * sizeof(int))
[...]
free(array)
So in most OS'es it is not possible due to the way they are implemented.
However theoretically allocating large chunk of memory in fact allocate many smaller blocks which could be deallocated this way, but still it would deallocate smaller blocks at a time not one-by-one.
All of new or new[] and even C's malloc do exactly the same in respect to memory: requesting a fix block of memory from the operating system.
You cannot split up this block of memory and return it partially to the operating system, that's simply not supported, thus you cannot delete a single element from the array either. Only all or none…
If you need to remove an element from an array all you can do is copy the subsequent elements one position towards front, overwriting the element to delete and additionally remember how many elements actually are valid – the elements at the end of the array stay alive!
If these need to be destructed immediately you might call the destructor explicitly – and then assure that it isn't called again on an already destructed element when delete[]ing the array (otherwise undefined behaviour!) – ending in not calling new[] and delete[] at all but instead malloc, placement new for each element, std::launder any pointer to any element created that way and finally explicitly calling the constructor when needed.
Sounds like much of a hassle, doesn't it? Well, there's std::vector doing all this stuff for you! You should this one it instead…
Side note: You could get similar behaviour if you use an array of pointers; you then can – and need to – maintain (i.e. control its lifetime) each object individually. Further disadvantages are an additional level of pointer indirection whenever you access the array members and the array members indeed being scattered around the memory (though this can turn into an advantage if you need to move objects around your array and copying/moving objects is expensive – still you would to prefer a std::vector, of pointers this time, though; insertions, deletions and managing the pointer array itself, among others, get much safer and much less complicated).
Consider the following code. This works for allocating a single array, but what if you needed to allocate a two dimensional array? How would you go about doing this?
#include <iostream>
void alloc(int **num)
{
*num = new int[5];
*num[0] = 5;
}
int main()
{
int *num;
alloc(&num);
std::cout << num[0] << std::endl;
delete [] num;
}
My goal is to pass **char into the function and have it allocated. Is this possible?
what if you needed to allocate a two dimensional array?
My goal is to pass **char into function and have it allocated.
So, what you want is a pointer to an array of pointers (each to an array)? That is different from an 2D array, although often treated as such for simplicity.
Just like you added an additional layer of indirection when you allocated that single array, you can add a layer of indirection to allocate an array of pointers, and the pointed to arrays of integers.
So, you could write a function like void alloc(int ***num). Yes, this is possible, but not very good design.
But using a pointer for the indirection makes the syntax more complex, and has the risk of a user passing a null pointer to the function. Instead, a better alternative would be to use a reference: void alloc(int **&num).
Since the function allocates something and "returns a pointer", it would make more sense to actually return the pointer: int** alloc(). Much prettier, isn't it? Less indirection is better.
Finally, there is the problem that a user of the function has to know how to delete the allocated memory. Was it allocated with new or new[]? Maybe even malloc? Or does the function perhaps return a pointer to a static object, that must not be deleted? The caller of the function cannot know that unless it is documented separately.
Also, what if one of the allocation fails? There will be an exception, and the earlier allocations will leak.
The C++ way to solve the above 2 problems is to use a RAII container to manage the memory. Since you apparently want to have an array with pointers to arrays, there is a ready made solution in the standard library for you: return a std::vector<std::vector<int>>. If you instead want a proper non-jagged 2D array i.e. a matrix, then you may want to write a custom RAII container for that, possibly using a flat std::vector<int> for the implementation. Note that a third party may already have implemented such container.
Your code looks like C to me. In C++ I would (maybe) use custom types and not do any manual dynamic allocation. For example
typedef std::vector<int> Row;
typedef std::vector<Row> Matrix;
Matrix initMatrix(int nRows,int nCols) {
return Matrix(nRows,Row(nCols));
}
well in that case you dont even need a function but you can just call the constructor (and let array allocate the memory for you).
I am dynamically allocating memory for an array in a function. My question is: once the function finishes running is the memory freed?
code:
void f(){
cv::Mat* arr = new cv::Mat[1];
...
}
No, memory allocated using new is not automatically freed when the pointer goes out of scope.
However, you can (and should) use C++11's unique_ptr, which handles freeing the memory when it goes out of scope:
void f(){
std::unique_ptr<cv::Mat[]> arr(new cv::Mat[1]);
...
}
C++11 also provides shared_ptr for pointers you might want to copy. Modern C++ should strive to use these "smart pointers", as they provide safer memory management with almost no performance hit.
No, it is not. You must free it by calling
delete[] arr;
But you should ask yourself whether it is necessary to allocate dynamically. This would require no explicit memory management:
void f(){
cv::Mat arr[1];
...
}
If you need a dynamically sized array, you could use an std::vector. The vector will internally allocate dynamically, but will take care of de-allocating it's resources:
void f(){
std::vector<cv::Mat> arr(n); // contains n cv::Mat objects
...
}
No. Every call to new needs to be matched up with a call to delete somewhere.
In your case arr iteself is a variable with automatic storage duration. This means that arr itself will be destroyed when it goes out of scope. However the thing that arr points to does not, because that is a variable that does not have autoatic storage duration.
The fact that arr itself has automatic storage duration can be used to your advantage, by wrapping the raw pointer in a class that destroys the stored pointer when the automatic object is destroyed. This object utilizes an idion known as RAII to implement a so-called "smart pointer". Since this is a very common requirement in well-designed applications, the C++ Standard Library provides a number of smart pointer classes which you can use. In C++03, you can use
std::auto_ptr
In C++11 auto_ptr has been deprecated and replaced by several other better smart pointers. Among them:
std::unique_ptr
std::shared_ptr
In general, it is a good idea to use smart pointers instead of raw ("dumb") pointers as you do here.
If what you ultimately need are dynamically-sized arrays, as supported by C99, you should know that C++ does not have direct support for them. Some compilers (notably GCC) do provide support for dynamically sized arrays, but these are compiler-specific language extensions. In order to have something that approximates a dynamically sized array while using only portable, Standards-compliant code, why not use a std::vector?
Edit: Assigning to an array:
In your comments you describe the way in which you assign to this array, which I have taken to mean something like this:
int* arr = new int[5];
arr[1] = 1;
arr[4] = 2;
arr[0] = 3;
If this is the case, you can accomplish the same using vector by calling vector::operator[]. Doing this looks uses very similar syntax to what you've used above. The one real "gotcha" is that since vectors are dyanamically sized, you need to make sure the vector has at least N elements before trying to assign the element at position N-1. This can be accomplished in a number of ways.
You can create the vector with N items from the get-go, in which case each will be value-initialized:
vector<int> arr(5); // creates a vector with 5 elements, all initialized to zero
arr[1] = 1;
arr[4] = 2;
arr[0] = 3;
You can resize the vector after the fact:
vector<int> arr; // creates an empty vector
arr.resize(5); // ensures the vector has exactly 5 elements
arr[1] = 1;
arr[4] = 2;
arr[0] = 3;
Or you can use a variety of algorithms to fill the vector with elements. One such example is fill_n:
vector<int> arr; // creates empty vector
fill_n(back_inserter(arr), 5, 0); // fills the vector with 5 elements, each one has a value of zero
arr[1] = 1;
arr[4] = 2;
arr[0] = 3;
No, of course not.
For every new you need precisely one delete.
For every new[] you need precisely one delete[].
Since you don't have the matching delete[], your program is broken.
(For that reason, the adult way of using C++ is not to use new or pointers at all. Then you don't have those problems.)
No. The array the allocated on the heap, you'll have to delete it before it goes out of scope:
void f() {
cv::Mat * arr = new cv::Mat[1];
// ...
delete [] arr;
}
Consider the following public method that adds an integer variable to a vector of ints(private member) in a class in C++.
KoolMethod()
{
int x;
x = 10;
KoolList.Add(x);
}
Vector<int>KoolList;
But is this a valid addition to a vector ??? Upon calling the method, it creates a local variable. The scope of this local variable ends the moment the execution control leaves the method. And since this local variable is allocated on a stack(on the method call), any member of KoolList points to an invalid memory location in deallocated stack which may or may not contain the expected value of x. Is this an accurate description of above mechanism ??
Is there a need for creating an int in heap storage using "new" operator everytime a value needs to be added to the vector like described below ????:
KoolMethod()
{
int *x = new int();
*x = 10;
KoolList.Add(x);
}
Vector<int*>KoolList;
But is this a valid addition to a vector?
Yes, a (standard library) vector stores copies.
Is there a need for creating an int in heap storage using "new" operator
If you don't want the objects to be copied or to work with polymorphic objects (see object slicing) you'd use pointers. In that case you should preferably avoid dealing with deallocation manually and use wrappers (smart pointers or pointer containers) though to get exception safety back.
A Vector<int> (at least if it is std::vector) stores elements by value, so calls to add() creates a copy of the parameter object and stores that copy into the array. Therefore it doesn't matter what happens with the original object, the copy within the vector is alive as long as the vector itself (unless removed or overwritten explicitly, of course).
A Vector<X*> may be more appropriate if you
want to work with polymorphic X objects,
don't want to copy objects of X e.g. because it's expensive or disallowed,
want to share the same objects between different parties.
Of course, none of these applies to int, only to real objects. Still, it is better to store smart pointers in the vector instead of raw pointers, e.g. vector<auto_ptr<X> > or vector<shared_ptr<X> >. These automatically manage the disposal of objects for you.
If you create a vector of ints, it will not be a vector of pointers. The integers are stored by value, no pointers involved, and therefore you won't run into any problems with invalid memory addresses.
Here's an example of code that would cause such a problem:
std::vector<int *> my_list;
void a_method() {
int value = 2; // allocated on the stack
my_list.push_back(&value); // pushes a pointer to the stack... not good
}
Think about this: adding to the standard vector creates copy of added object.
In the first code snippet, you use vector of ints, so you'll add the copy of local int and everything is fine.
In the second code snippet you use vector of pointers to int, so you'll add the copy of a pointer (not the copy of the object this pointer is pointing to). Since the object pointed by the pointer will be still valid after leaving the method (it's initialized using new operator and it's not deleted anywhere) everything will be fine too.
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.