I made a 2D array on the heap of some objects:
Step (1)
Obj **arr = new Obj *[n];
for (int i=0;i<n;i++)
{
arr[i] = new Obj[n];
}
// so this creates 2D arr[n][n]...then when I delete it:
Step (2)
for (int i=0;i<n;i++)
{
delete [] arr[i];
}
delete [] arr;
So I'm still not sure what this delete does. Does it run the destructor of Obj and flag the OS telling it this is now available memory.
Now what I REALLY do not understand is that when I do Step (1) again (after I deleted), I get these objects initialized to weird values, yet this doesn't happen the first time I do it (all zero-initialized). Did I just get lucky the first time?
AFAIK, the following code will NOT give you weird values, no matter how many times you repeat deleting and newing.
#include <iostream>
using namespace std;
class Foo
{
public:
Foo(): val(-2) { cout << "ctor" << endl; }
~Foo() { cout << "dtor: " << val << endl; }
private:
int val;
};
int main()
{
Foo **arr = new Foo *[2];
for (int i = 0; i < 2; ++i)
arr[i] = new Foo[2](); // <- for builtin type, () is required to initialized to zero.
for (int i = 0; i < 2; ++i)
delete [] arr[i];
delete [] arr;
return 0;
}
Relevant post: Operator new initializes memory to zero
As to what happens to pointers after you delete them, please see this post: C - What happens to an array of pointers when the array is freed?
Your example lacks the declaration of Obj.
new[] allocates memory and calls the constructor of each element
If the constructor does not alter memory, you will see some random values - maybe zeros.
delete[] calls the destructor of each element previously allocated with new[] and deallocates the memory, finally.
In a debugging compilation the memory might be filled with some bytes indicating the deallocation.
Doing new[] right after the deallocation might show indicator bytes.
Related
Consider that I have an array of pointers declared as:
MyObject** myArr = new MyObject*[someSize] ;
And then I assign some objects by
myArr[i] = myObjectInstance
Now, I want to delete every element pointed to by each pointer of this array. So what is the correct way to do that?
I don't think delete[] myArr works.
Delete each object first, then the whole array:
for(int i = 0; i < someSize; i++)
{
delete myArr[i];
}
delete[] myArr;
You can use the standard algorithm std::for_each and the function object std::default_delete.
Here is a demonstrative program
#include <iostream>
#include <memory>
#include <algorithm>
struct A
{
static size_t i;
A() { i++; }
~A() { std::cout << --i << ": ~A()\n"; }
};
size_t A::i = 0;
int main()
{
const size_t N = 10;
A **p = new A *[N];
for ( size_t i = 0; i < N; i++ )
{
p[i] = new A();
}
std::for_each( p, p + N, std::default_delete<A>() );
delete []p;
return 0;
}
Its output is
9: ~A()
8: ~A()
7: ~A()
6: ~A()
5: ~A()
4: ~A()
3: ~A()
2: ~A()
1: ~A()
0: ~A()
If you want to delete the elements of the array in the reverse order relative to the order of creating them then you can write
std::for_each( std::reverse_iterator<A **>( p + N ),
std::reverse_iterator<A **>( p ), std::default_delete<A>() );
for (int i = 0; i < someSize; ++i)
delete myArr[i];
That could do the trick. However you go about it, you will have to visit each element and delete it individually, and then delete the array with delete [] myArr;.
But dynamically allocating arrays can be messy business. In keeping up with SO traditions, I'm going to recommend std::vector (or whatever STL container makes sense) if you are able to use it. You would still have to individually delete all elements, but now you don't have to worry about the array itself.
As mentioned in the comments to your question, if you use smart pointers to each element, then you don't have to manually delete anything.
Acctualy, delete[] myArr is right, because myArr is dynamically allocated object.
You might need to deallocate some myArr[i] before if you do any myArr[i] = myObjectInstance where myObjectInstance is dynamically allocated, example:
myArr[i] = new MyObject;
delete myArr[i]; is going to crash if:
MyObject m;
myArr[i] = &m;
In the case of all positions being dynamically allocated, you can use a for to free memory:
for (int i = 0; i < someSize; ++i)
delete myArr[i];
Let us assume that all the myObjectInstance are pointers to heap allocated objects (if not so, see #JoãoPaulo 's answer), and no custom new or delete is involved.
for (size_t idx = 0; idx < someSize; ++idx)
delete myArr[idx];
delete[] myArr;
What is the potential pitfall?
Well, there are many. What if only some of the array elements are initialized? The other would be in an indetermined state, and deleting them leads to undefined behavior.
Also, what if multiple array elements points to the same object? Then you are trying to delete an object multiple times. That also leads to undefined behavior.
This doesn't mean you cannot use this naive method, it just reminds you of some pre-conditions:
Make sure every element of array is initialized to either "pointer to some heap allocated object" or nullptr (deleting nullptr is safe).
Make sure you don't delete an object twice.
I am using a array of pointer's declared within a class to point to another array. When a pointer array element is initialised to a value within main that value is also carried to the array element it is pointing to. The following code show this and it works fine. However if I initialise the pointer within the init class function I get a segfault. Also if I try to access an element from the pointer array not initialised in main I also get a segfault.
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
class testclass {
public:
double *Wgt;
double* *LWgt;
void init() {
Wgt = new double[26];
LWgt = new double*[26];
//segfault from here
*LWgt[5] = 22.34543;
}
};
int main() {
testclass *node;
node = new testclass[10];
for (int i = 0; i < 10; i++) {
node[i].init();
}
for (int i = 0; i < 5; i++) { //init_nconn here
node[i].LWgt[23] = &node[i + 5].Wgt[12];
}
node[6].Wgt[12] = 50.6987;
node[8].Wgt[12] = 0.999923;
cout << *node[1].LWgt[23] << *node[3].LWgt[23] << "--\n";
//No segfault
*node[1].LWgt[23] = 33.234;
cout << node[6].Wgt[12] << "---\n";
//No segfault here
cout << *node[1].LWgt[23] << "---\n";
//Segfault from here
cout << *node[3].LWgt[5] << "---\n";
}
Is there a way to initialise the pointer array within a class function without leading to a segfault?
LWgt = new double*[26];
allocates memory for 26 double* but does not allocate memory for the pointers themselves.
The line
*LWgt[5] = 22.34543;
causes undefined behavior since memory hasn't been allocated for any of the elements of LWgt.
In order to be able to use that, you have to allocate memory for LWgt[5] first.
LWgt[5] = new double[<SOME_SIZE>]; // Allocate an array
or
LWgt[5] = new double; // Allocate just one element.
That's because none of the pointers stored inside LWgt actually point to anything valid yet. Remember that a pointer will be initialized by the runtime with some random value that may or may not be a valid address. When you try to stuff a value inside an invalid address you're going to get an error.
You need to initialize the pointers inside LWgt to point to some actual double memory locations before you can assign any values to them:
void init() {
Wgt = new double[26];
LWgt = new double*[26];
for(int i = 0; i < 26; i++)
LWgt[i] = new double;
//segfault from here
*LWgt[5] = 22.34543;
}
As a side note, this kind of initialization is probably best done inside a constructor for your class rather than a special initialization function. The point of constructors is that they always run automatically when the class is instantiated. You don't have to worry about remembering to call an init function right after you create the object.
Lwgt is an array of pointers to double. You'd have to allocate each element in the array or remove the ** in the declaration.
My code pass the compiler, but I have a question about the concept of the pointer.
main.cpp:
int main(int argc, const char * argv[])
{
int inputPuzzle[3][3];
std::cout << "Set the puzzle: " << "\n";
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
std::cin >> inputPuzzle[i][j];
}
}
puzzle puzzle_1 = *new puzzle(inputPuzzle);
puzzle_1.display();
return 0;
}
puzzle.h:
class puzzle
{
public:
puzzle();
puzzle(int [][maxCol]);
~puzzle();
public:
int puzz [maxRow][maxCol];
};
puzzle.cpp:
puzzle::puzzle(int a[][maxCol])
{
for (int i = 0; i < maxRow; i++) {
for (int j = 0; j < maxCol; j++) {
puzz[i][j] = a[i][j];
}
}
}
My question is about the statement :puzzle puzzle_1 = *new puzzle(inputPuzzle);
Why do I have to add "*" in front of the new object in which I want to assign a 2D array ?
You're programming C++, where new returns a pointer. When you use the asterisk it's the dereference operator, and basically turns a pointer into a non-pointer.
Using the dereference operator like that means that you actually lose the pointer created by new, and you can not free that allocated memory with delete which, of course, leads to a memory-leak.
To avoid losing the pointer, you have to declare the variable as a pointer:
puzzle* puzzle_1 = new puzzle(inputPuzzle);
Then you have to use the pointer member selector operator instead when accessing members:
puzzle_1->display();
And, to avoid leaking memory, when you're done with the pointer you must delete it:
delete puzzle_1;
However, in C++ there is seldom any need to use pointers; instead just declare it as a normal variable:
puzzle puzzle_1(inputPuzzle);
puzzle_1.display();
Unrelated to your question, but if maxRow or maxCol is larger than 3, then you will read from outside the memory for the array inputPuzzle. This will lead to undefined behavior.
The most important part here is the new keyword. It returns a pointer to the newly instantiated object. Check the Dynamic memory allocation for more information and to understand when and how to use pointers, and how the new keyword works.
Now, we know that the new keyword returns a pointer, and you want to obtain an object not a pointer, hence you have to dereference your pointer.
Two correct solutions now:
// without pointers
puzzle puzzle_1(inputPuzzle); // initialize the object without going through a copy
puzzle_1.display();
// with pointers
puzzle *puzzle_1 = new puzzle(inputPuzzle);
puzzle_1->display(); //notice that we used -> here as it's a pointer
// do stuffs here
delete puzzle_1; // free the memory
After writing the code below:
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
} Node;
int main() {
Node* arr[10];
for(int i = 0; i < 10; i++) {
arr[i] = &Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i]->value << endl;
}
I saw that the code prints only 9's instead of all the numbers from 0 to 9 it was supposed to.
After debugging the code i saw that address of arr[i] for each i are the same, and Node(i) have freed the space for arr[i] only once, and after that the only thing it is value = index without freeing any other space. Why?
This line: arr[i] = &Node(i); is storing a pointer to a temporary object. Node(i) creates a temporary object that can be destructed at the end of the statement, at which point all references to it become invalid meaning the results of any code that dereferences arr[i] will be undefined. The reason in this case you get all 9's is because the compiler is optimizing the code -- since only 1 temporary Node(i) is being created at a time, the compiler is just reusing that memory each time through the loop.
To fix the problem, allocate memory off the heap for each object: arr[i] = new Node(i);. Then when you are done using them you will also need to remember to delete each one:
for (int i=0; i < 10; ++i) {
delete arr[i];
}
If you want to investigate farther, try adding some code to your Node class to see what's happening: for example print out the address of this in your constructor, and/or create a destructor that just prints a message out so you can see it being called.
To create new objects, use new Node(i) otherwise you are creating temporary objects on the stack which is why they are all the same.
Remember to call delete on each object that you get back from new.
&Node(i)
This expression creates a temporary variable and returns its address. The temporary is then destroyed, and the next time the expression is evaluated, another temporary is created in the same place — hence the identical addresses.
You should probably eliminate the use of pointers, and introduce a default value for Node.
#include <iostream>
using namespace std;
typedef struct Node {
int value;
Node(int index) {
value = index;
}
Node() : value( 0 ) {} // allow default construction
} Node;
int main() {
Node arr[10]; // default-construct array values
for(int i = 0; i < 10; i++) {
arr[i] = Node(i);
}
for(int i = 0; i < 10; i++)
cout << arr[i].value << endl;
}
Do not use new Node for each object individually. Always use a container object to manage a group of objects with similar semantics. You might use std::vector here, or std::array if you have it. The overhead introduced by std::vector will be less than that introduced by new.
I am storing pointers to elements of a vec_A in an array A* a_ptrs[3] . Assume that vec_A will not be resized. So, a_ptrs[i] will point to the correct element.
My question is:
Suppose A* a_ptrs[3] is declared in a class B. Since it is not created using 'new' I am guessing I don't need to delete it in the destructor. Am I right??
class A {
public:
int getNumber();
A(int val);
~A(){};
private:
int num;
};
A::A(int val){
num = val;
};
int A::getNumber(){
return num;
};
int main(){
int i =0;
int num;
std::vector<A> vec_A;
for ( i = 0; i < 10; i++){
vec_A.push_back(A(i));
}
A* a_ptrs[3];
a_ptrs[0] = &vec_A[0];
a_ptrs[1] = &vec_A[3];
a_ptrs[2] = &vec_A[5];
for (i = 0; i<3; i++){
std::cout<<"\n: a_ptrs[i].getNumber() = "<<a_ptrs[i]->getNumber();
}
std::cout << "\nPress RETURN to continue...";
std::cin.get();
return 0;
}
Yep, thats correct. You don't need to use delete. The only issue is if the vector is resized e.g. by calling push_back etc - but you called that out in your post.
Yes, delete is used only for variables allocated with new.
Correct, since there is no dynamic memory allocation in the program.
My Suggestion is to use vector.reserve() function to reserve the size of the vector which will improve program performance.
Basically when you add an element to CArray(MFC) or std::vector it reallocates necessary memory and copies the elements so it will lead to memory fragmentation and will degrade program speed.