Reputation: 13
Not sure what I'm doing wrong here. I'm trying to add a new element and up until the function ends it appears to have worked. But once I try to access anything in it after I get a segmentation fault.
This is just sample code I'm using to try and figure out what I'm doing wrong, with console output to help determine current values.
#include <iomanip>
#include <iostream>
using namespace std;
class foo
{
private:
int z;
public:
foo(int);
int getz();
void setz(int);
};
foo::foo(int zz)
{
z = zz;
}
int foo::getz()
{
return z;
}
void foo::setz(int zz)
{
z = zz;
}
void boo(foo** x, unsigned* n)
{
foo** b = new foo*[3];
for (int i=0; i<2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
Upvotes: 0
Views: 70
Reputation: 15277
The problem is, how you pass your array to your function "boo".
As a general notice, please let me recap how we can use in/out parameters for functions. As you may have heard, we can
You are passing the foo** as value. That is the reason why it will not work. Delete the parameter will work, but the assignment of x to b will not be visible to the outside world. And after the function "boo" returns, a will be deleted.
Let us look at the good all "swap" example.
// Call by value, will not work. "a" will be changed, but it is a copy
void swapv(int a, int b) {
int temp = a;
a = b;
b = tmp;
}
// Call by address(via pointer) will work. Dereferencing is necessary
void swapp(int *a, int *b) {
int temp = *a;
*a = *b;
*b = tmp;
}
// Call by reference. Recommended solution. Will simply work with same variable names
void swapr(int &a, int &b) {
int temp = a;
a = b;
b = tmp;
}
As you can see. The passing by reference approach is most simple.
Again, what you do is passing "foo**" by value. By the way, "n" is passed via pointer. If you use a typedef
or using
statement, it will get very obvious.
Look at the following piece of code using a using
-alias statement.
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr x, unsigned* n)
{
fooPtrPtr b = new fooPtr[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
Now you can immediately see the problem. You see immediately that "x" is passed by value to "boo".
But this leads then directly to the recommended and easy solution. Pass it by reference. Like the below:
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr& x, unsigned& n)
{
fooPtrPtr b = new fooPtr[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
n++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, s);
cout << s;
cout << a[0]->getz();
return 0;
}
With pointers and pointers to pointers, using
or typedef
will be very helpful.
Very simple. And without using using
the code will be not so easy to understand and could look like the below.
One ampersand "&" after foo**
solves the whole problem.
void boo(foo**& x, unsigned& n)
{
foo** b = new foo*[3];
for (int i = 0; i < 2; i++)
b[i] = x[i];
b[2] = new foo(5);
cout << x[0]->getz() << x[1]->getz();
delete[]x;
x = b;
cout << x[0]->getz() << ' ' << x[1]->getz() << ' ' << x[2]->getz();
b = nullptr;
n++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(a, s);
cout << s;
cout << a[0]->getz();
return 0;
}
And last but not least also the version with pass by address / via pointer. Then a lot of dereferencing is necessary, which makes code even harder to read:
void boo(foo*** x, unsigned *n)
{
foo** b = new foo*[3];
for (int i = 0; i < 2; i++)
b[i] = (*x)[i];
b[2] = new foo(5);
cout << (*x)[0]->getz() << (*x)[1]->getz();
delete[](*x);
*x = b;
cout << (*x)[0]->getz() << ' ' << (*x)[1]->getz() << ' ' << (*x)[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
foo** a = new foo*[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(&a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
We can also use aliases to make this a little more readable, but still clumsy.
using fooPtrPtr = foo**;
using fooPtr = foo*;
void boo(fooPtrPtr* x, unsigned *n)
{
fooPtrPtr b = new fooPtr [3];
for (int i = 0; i < 2; i++)
b[i] = (*x)[i];
b[2] = new foo(5);
cout << (*x)[0]->getz() << (*x)[1]->getz();
delete[](*x);
*x = b;
cout << (*x)[0]->getz() << ' ' << (*x)[1]->getz() << ' ' << (*x)[2]->getz();
b = nullptr;
(*n)++;
}
int main() {
fooPtrPtr a = new fooPtr[2];
unsigned s = 2;
a[0] = new foo(1);
a[1] = new foo(2);
boo(&a, &s);
cout << s;
cout << a[0]->getz();
return 0;
}
Upvotes: 1