Dynamic array of pointers, how to do it correctly? - c++

I know, I could use std::vector or something like that, but I want to know where I think wrong. In the example below, only p3 is in my eyes really a pointer to an array of pointers and is used in the way I would expect. Using p1 instead looks kind of wrong to me because it looks like p1 is also an array of pointers like p2 is and not a pointer to an array of pointers, except for the delete thing. So when I try to use p2 as I do use p3:
(*p2)[i] = new Foo(i);
the error is:
ambiguous overload for ‘operator=’ (operand types are ‘Foo’ and ‘Foo*’)
The question is:
Why do I have to use a cast in the line where p3 is allocated?
Is that assignment for p3 correct or does it just work by incident?
#include <iostream>
using namespace std;
class Foo
{
public:
Foo (int key)
: key(key)
{}
int show() const
{
return key;
}
private:
int key;
};
int main (int, char**)
{
int aSize = 10;
using FooP = Foo *;
FooP *p1 = new FooP[aSize];
FooP p2[aSize];
FooP (*p3)[] = (FooP (*)[]) new FooP[aSize];
for (int i=0; i < aSize; i++)
{
p1[i] = new Foo(i);
p2[i] = new Foo(i + aSize);
(*p3)[i] = new Foo(i + aSize * 2);
}
for (int i=0; i < aSize; i++)
{
cout << p1[i]->show() << ", "
<< p2[i]->show() << ", "
<< (*p3)[i]->show()
<< endl;
delete p1[i];
delete p2[i];
delete (*p3)[i];
}
cout << endl;
delete [] p1;
delete [] p3;
return 0;
}

So the explanation is, that the operator "new" in case of an array, always returns a pointer to the first element and not, as I expected, a pointer to the array of pointers.
So the cast I used when assigning the allocated memory to the variable p3 is valid and would not cause any memory corruption, right?
Thanks to #exprosic for the helpful hint in the comments to https://en.cppreference.com/w/cpp/language/new
Quote from there:
The new expression attempts to allocate storage and then attempts to construct and initialize either a single unnamed object, or an unnamed array of objects in the allocated storage. The new-expression returns a prvalue pointer to the constructed object or, if an array of objects was constructed, a pointer to the initial element of the array.

Related

Deleting corresponding element pointed to by each element of an array of pointer in c++

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.

How to correctly initialise pointers within class function?

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.

c++ assign a 2D array to an Object

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

How are arrays stored and deleted in memory?

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.

Change the value of elements in the array by pointers - vector<int> C++ [duplicate]

This question already has answers here:
C++ trying to swap values in a vector
(5 answers)
Closed 9 years ago.
I use Visual Studio 2012. I've created my own function which works like sprintf(&a).
And i need to resolve problem: how do I swap two specific pointer elements?
Here is my code:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(vector<int>* a, vector<int>* b)
{
vector<int>* tmp = NULL;
*tmp = *a;
*a = *b;
*b = *tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(*test[0], *test[1]);
printf("%d %d", test[0], test[1]);
return 0;
}
I got an error:
terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
What is wrong? What i should change?
I am unsure as to what you are trying to do, but I am going to guess you are trying to swap two values in a vector. As your comments have said, using the swap would work, but I think you are confused as to what your code actually does. Let's go step by step here:
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(*test[0], *test[1]); // *test[0] is the same as *(test[0])
When you perform *test[0], this is the same as *(test[0]). This means to dereference/look at the value in memory address test[0], which is 5. That memory address is inaccessible for you, so it will cause a seg fault.
Second problem:
void swap_spec(vector<int>* a, vector<int>* b)
{
vector<int>* tmp = NULL;
*tmp = *a;
*a = *b; // This says, get whatever vector is pointed at b, and copy it to the memory location variable a points to.
*b = *tmp;
}
Since you are passing in pointers to vectors, what you're saying here is to swap the two vectors, not the values inside them. But when you call this with:
swap_spec(*test[0], *test[1]);
The type of test[0] is an int, the type of *(test[0]) is a dereferenced int (which is a seg-fault, but supposedly another int type), but the parameter type is a vector * (a pointer to a vector), which is already inconsistent with the arguments you pass in. See how this is already wrong in multiple levels.
So given all those information, it looks like you are trying to swap two values in the vector. You can do this one of two ways. You can do this with pointers:
void swap_spec(int *a, int *b) {
int tmp = *a;
*a = *b; // Go to address location where variable a points to, and assign whatever value is at memory location where variable b points to
*b = tmp;
}
swap_spec(&test[0], &test[1]); // Pass in address of where test[0] and test[1] points to
// Note that type of &test[0] is an int * (Consistent with parameter)
Or with references:
void swap_spec(int &a, int &b) {
int tmp = a;
a = b; // Since you are using references, this will actually modify test[0] at its memory location
b = tmp;
}
swap_spec(test[0], test[1]); // Since you are using references, you don't need to pass in the address.
The second way is the same as the standard library's swap (http://www.cplusplus.com/reference/algorithm/swap/). References are sometimes (or perhaps generally) favored because it produces cleaner code (less * operators used) and hence less confusion.
You declare your function to take pointers to vector<int>s as parameters but you then pass is something else. *test[1] is dereferencing test[1] which is the int 4. You are treating ints 4 and 5 as pointers which is problematic.
It is not entirely clear what you are trying to accomplish, but if you just want to swap two elements of a vector, why not something like:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(vector<int> & a, size_t i, size_t j)
{
int tmp;
tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
printf("%d %d \n", test[0], test[1]);
swap_spec(test, 0, 1);
printf("%d %d \n", test[0], test[1]);
return 0;
}
Suppose what you really want do to is to swap two specific pointer elements. Then there are few possible errors. First the vector you created is an integer array instead of an pointer vector:
vector<int> test(4);
Second, in your function interface, the types of your input parameters are in fact a pointer to an integer vector (which means you would like to swap two vectors, instead of two integer pointers).
void swap_spec(vector<int>* a, vector<int>* b)
Third, since your vector is an integer vector, applying the indirection Operator * will let you get an error (*a means give me the content stored in the memory location described in variable a).
swap_spec(*test[0], *test[1]);
The following is how to swap "two integer pointers":
#include <stdio.h>
void swap_spec(int** a, int** b) // the function which swaps int pointers.
{
int** tmp;
*tmp = *a;
*a = *b;
*b = *tmp;
}
int main()
{
int** test = new int*[4]; // create an array of int integers
for (int i = 0; i < 4; ++i) {
test[i] = new int;
}
*test[0] = 5;
*test[1] = 4;
*test[2] = 3;
*test[3] = 2;
printf("%d %d\n", *test[0], *test[1]);
swap_spec(&test[0], &test[1]); // pass their addresses instead
printf("%d %d\n", *test[0], *test[1]);
for (int i = 0; i < 4; ++i) {
delete test[i];
}
delete[] test;
return 0;
}
If what you would like to do is simply swapping two int elements in a vector, then std::swap() or the answers proposed by #Narfanator and #Spook should work.
Alright, I think this should do you, but my C's a little rusty:
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
void swap_spec(int* a, int* b)
{
int tmp = NULL;
tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
vector<int> test(4);
test[0] = 5;
test[1] = 4;
test[2] = 3;
test[3] = 2;
swap_spec(&test[0], &test[1]);
printf("%d %d", test[0], test[1]);
return 0;
}
What I have done here is "swap the values at two memory locations", and then passed in the locations of the first and second element of your vector.
Let's go over your code, see if we can't clear some of what's going on up:
void swap_spec(vector<int>* a, vector<int>* b)
This says: Give me two pointers to vectors storing ints. When you're dealing with the elements of a vector, you just pass around the type stored in the vector: in this case, int:
void swap_spec(int a, int b)
However, C/C++ are pass-by-value, which means the passed values would be copied, and then used locally - meaning, you could not effect the overal program environment by passing in the values.
You got this, which is why you passed in pointers.
Instead, you need to pass in pointers to the values:
void swap_spec(int* a, int* b)
Technically, you're passing-by-value a memory address. Anyway - This lets you interact with memory (and this variables, objects, etc) outside of the function, in the overal program.
swap_spec(*test[0], *test[1]);
This passes in the values stored at the memory locations stored in test[0], which is invalid, because it's five.
What you want is:
swap_spec(&test[0], &test[1]);
Which pass in the memory addresses of those values, which is what you wanted.
I guess, that you want to swap elements inside the vectors, not the vectors themselves. So firstly, don't swap std::vector<int> *, but just int *.
Secondly, pointers are not needed here at all. Use a function:
void swap_spec(std::vector<int> & vec, int index1, int index2)
{
int tmp = vec[index1];
vec[index1] = vec[index2];
vec[index2] = tmp;
}
Then call it like this:
swap_spec(test, 0, 1);