Declaration and assignation of dynamic 3d array - c++

I have made the next class for a 3d array. Declaring a variable as, for example
Grid3d n = Grid3d(2,2,2);
n(0,0,0) = 1;
works fine, but declaring it as
Grid3d n;
n = Grid3d(2,2,2);
n(0,0,0) = 1;
Gives me a segmentation fault, the problem seems to be the default constructor, but i don't know how to fix it, any clue?
#ifndef _GRID3D_
#define _GRID3D_
#include <iostream>
#include <cmath>
#include <cassert> // assert()
using namespace std;
class Grid3d
{
private:
int L;
int M;
int N;
double *** G;
public:
Grid3d(int,int,int);
Grid3d();
Grid3d(const Grid3d &);
~Grid3d();
double & operator()(int,int,int);
};
#endif
//Constructor
Grid3d::Grid3d(int L,int M,int N)
:L(L), M(M), N(N)
{
int i,j,k;
G = new double ** [L];
for (i=0;i<L;i++){
G[i] = new double * [M];
for (j=0;j<M;j++){
G[i][j] = new double [N];
for (k=0;k<N;k++){
G[i][j][k] = 0;
}
}
}
}
//Constructor vacĂ­o
Grid3d::Grid3d()
:L(0), M(0), N(0)
{
G = NULL;
}
//Constructor copia
Grid3d::Grid3d(const Grid3d &A)
:L(A.L), M(A.M), N(A.N)
{
G = new double ** [L];
int i,j,k;
for (i=0;i<L;i++){
G[i] = new double * [M];
for (j=0;j<M;i++){
G[i][j] = new double [N];
for (k=0;k<N;k++){
G[i][j][k] = A.G[i][j][k];
}
}
}
}
//Destructor
Grid3d::~Grid3d()
{
// Libera memoria
for (int i=0;i<L;i++){
for (int j=0;j<M;j++){
delete [] G[i][j];
G[i][j] = NULL;
}
delete [] G[i];
G[i] = NULL;
}
delete G;
G = NULL;
}
double& Grid3d::operator()(int i,int j,int k)
{
assert(i >= 0 && i < L);
assert(j >= 0 && j < M);
assert(k >= 0 && k < N);
return G[i][j][k];
}
Assignment operator
Grid3d Grid3d::operator = (const Grid3d &A)
{
if (this == &A) {return *this;};
if (G != NULL){
// Libera memoria
for (int i=0;i<L;i++){
for (int j=0;j<M;j++){
delete [] G[i][j];
G[i][j] = NULL;
}
delete [] G[i];
G[i] = NULL;
}
delete G;
G = NULL;
}
L = A.L;
M = A.M;
N = A.N;
G = new double ** [L];
int i,j,k;
for (i=0;i<L;i++){
G[i] = new double * [M];
for (j=0;j<M;i++){
G[i][j] = new double [N];
for (k=0;k<N;k++){
G[i][j][k] = A.G[i][j][k];
}
}
}
return *this;
}

You have dynamically allocated memory, but you have not followed the rule of three. You are missing an assignment operator, so when you do this:
Grid3d n;
n = Grid3d(2,2,2); // both RHS temporary and n point to the same data.
n(0,0,0) = 1; // Accessing deleted memory: undefined behaviour.
you will have two attempted de-allocations of the same memory, because you have n's pointer pointing to the same memory as the temporary used to assign to it in the second line. When the temporary dies, it de-allocated it's memory. When n dies, it tries to de-allocate the same memory. Furthermore, any access to that memory after the second line is undefined behaviour.

It's a trivial typo. I'll point out the line, and I'll let you spot where it's gone wrong:
for (j=0;j<M;i++)
That is, aside from the missing assignment operator, which makes the original constructed object in n = Grid3d(2,2,2); be freed, and thus you are accessing G[i][j][k] in operator() with NULL pointers.

Related

Return struct created from new struct within function

In this code, does the array pointer in the struct returned from the function point to the same block of memory that was defined with the new struct?
#include <iostream>
#include <math.h>
struct Arr
{
const int Col;
const int Row;
double* CAR{ new double[Col * Row] };
Arr(int y, int x) : Col(x), Row(y) {}
void Del() { delete[] CAR; }
int Indx(int y, int x) { return (x + y * Col); }
int Size() { return Col * Row; }
void Print(std::string title);
};
void Arr::Print(std::string title)
{
std::cout << title << '\n';
for (int I = 0; I < Row; I++)
{
for (int In = 0; In < Col; In++)
{
std::cout << CAR[Indx(I, In)] << " / ";
}
std::cout << '\n';
}
}
const Arr retfunc(std::string h, Arr& a, Arr& b)
{
Arr* temp = NULL;
if (h == "Had")
{
temp = new Arr(a.Row, a.Col);
for (int I = 0; I < a.Row; I++)
{
for (int In = 0; In < a.Col; In++)
{
temp->CAR[temp->Indx(I, In)] = a.CAR[a.Indx(I, In)] * b.CAR[b.Indx(I, In)];
}
}
} Arr T = *temp; return T;
}
int main()
{
int val = 5;
Arr a(2, 2);
Arr b(2, 2);
for (int I = 0; I < 2; I++)
{
for (int In = 0; In < 2; In++)
{
a.CAR[a.Indx(I, In)] = 10.0 / val + In;
b.CAR[b.Indx(I, In)] = 8.0 / val + In;
}
}
a.Print("a");
b.Print("b");
Arr S = retfunc("Had", a, b);
S.Print("S");
S.Del();
}
So essentially then, does calling delete on S clear the same memory that was allocated in retfunc?
You should just have a return *temp at the end of retfunc which is declared to return an Arr object. Once this is fixed, S.Del() correctly releases the memory block allocated in retfunc.
Yet this is terrible code. You fail to release the blocs allocated in a and b object. Not an error because the end of the program will release them, but this is a recipe for memory leaks. Moreover, you have a manual allocated memory block in constructor, but no explicit copy constructor nor assignment operator. If you write:
Arr c = a;
both c and a will share the same CAR array which may or not be what you want.
Long story short, I think that this is not a blatant error but at least an antipattern.
For starters the function retfunc has a memory leak because the object temp dynamically allocated within the function is not freed.
As the class does not have an explicit copy constructor then in this declaration
Arr T = *temp
there is used member-wise copying of data members of the object temp to the object T. The value of the pointer CAR of the object temp will be copied in the pointer CAR of the object T and will be a valid pointer due to the life-time of the dynamically allocated object temp.
When within a class there is dynamically allocated memory then you need to write an explicit destructor, copy constructors for lvalues and rvalues and copy assignment operators for lvalues and rvalues.

how to have a copy constructor for vector?

I simulated a vector but the constructor doesn't work; when I call pop() function it assigns garbage value to my old object in vector class.
vector(vector &v) {
vec = new T[v.size()];
memcpy(vec, v,v.size());
size_arr = v.size();
}
here's entire code:
#include <iostream>
using namespace std;
template <typename T>
class vector {
int size_arr;
T * vec = new T;
public:
vector(/*int _size*/) {
vec = new T[0];
size_arr = 0;
};
~vector() {
size_arr = 0;
delete[] vec;
};
vector(vector &v) {
vec = new T[v.size()];
memcpy(vec, v,v.size());
size_arr = v.size();
}
void push_back(T data) {
T *temp = new T[size_arr + 1];
for (int i = 0; i < size_arr; i++)
temp[i] = vec[i];
temp[size_arr] = data;
size_arr++;
delete[] vec;
vec = temp;
};
void push_front(T data){
int j;
T *temp = new T[size_arr + 1];
for ( j = size_arr; j >= 0;j--) {
temp[j + 1] = vec[j];
}
temp[0] = data;
delete[] vec;
vec = temp;
size_arr++;
};
void insert(int index, T data) {
int j;
T *temp = new T[size_arr + 1];
for (int i = 0; i < size_arr ;i++)
temp[i] = vec[i];
for (int i = 0; i < size_arr;i++) {
if (i == index) {
for ( j = size_arr; j >=i;j--) {
temp[j+1] = vec[j];
}
temp[j + 1] = data;
delete[] vec;
vec = temp;
size_arr++;
}
}
};
void pop() {
T *temp = new T[size_arr - 1];
for (int i = 0; i < size_arr-1;i++)
temp[i] = vec[i];
size_arr--;
delete[] vec;
vec = temp;
};
void Delete(int index)
{
T *temp = new T[size_arr - 1];
for (int i = 0; i < index;i++)
temp[i] = vec[i];
for (int i = 0; i < size_arr;i++) {
if (i == index) {
for (int j = i; j < size_arr-1;j++) {
temp[j] = vec[j + 1];
}
size_arr--;
delete[] vec;
vec = temp;
}
}
};
int search(T data) {
for (int i = 0; i < size_arr;i++) {
if (vec[i] == data) {
return i;
}
}
return -1;
};
int size() { return size_arr; };
};
int main() {
vector <int>test;
test.push_front(2);
test.push_front(3);
test.push_back(0);
test.push_back(-1);
test.insert(2, 2);
test.pop();
vector <int > test1;
test1 = test;// problem
test1.pop();
}
The problem is the line test1 = test;// problem, which does not call the copy constructor, but the assignment operator. You did not declare this operator, so the compiler will use the default implementation, which simply copies all member. So, after the assignment test1.vec and test.vec point to the same memory location.
When you change the line (and the one above it) to vector <int > test1{test};, it will call your copy constructor.
You also forgot to #include <cstring> for memcpy, which you should not use for non-POD types.
You have to multiply the size in memcpy with sizeof(T), because memcpy works on bytes, not on types. You also have to use v.vec instead of v.
Here is the fixed version: https://ideone.com/JMn7ww
I think the problem is in your copy operator. You use memcpy() which is a c function. Which should in itself not be a problem (apart from it being not so nice in many opinions). But since memcpy() is a c function, it doesn't know about types, and it takes its size arguments as a count of bytes.
the element you put in is int which is probably 4 bytes. So when your copy contstructor gets called, and the original has 3 elements, there will be 12 bytes in your array, but malloc will only copy 3 of them.
The comments of other people about not properly copying template types are right, so if you make a vector of strings, you cannot just memcpy them, and assume the result will be new strings. For this answer i was assuming you using only basic types as your template arguments like int, or double.

Why this move construct have not been called?

I have wrote a useless class, containing move constructor, default constructor and other construct. But this code (useless four(one + two)) didn't call move constructor. By the way, I have another question. Is safe when I delete a null pointer?
class useless {
private:
int len;
char * p; // address of string
public:
~useless();// default deconstruct
explicit useless(int len);// len construct
useless(int len, char c);// two argument construct
useless(useless&& u); //move construct
useless operator+(const useless& u) const; // operator +
};
useless::useless(int l) {
len = l;
p = new char[len];
}
useless::useless(int l, char c) {
len = l;
p = new char[len];
for(int i =0;i<len;i++){
p[i] = c;
}
}
useless::useless(useless&& u) {//move construct
len = u.len;
p = u.p;
u.p = nullptr;
u.len = 0;
}
useless::~useless() {
delete[] p;
}
useless useless::operator+(const useless &u) const {
useless re = useless(n + u.n);
for(int i =0; i < n; i++){
re.p[i] = p[i];
}
for(int i = n;i < re.n; i++){
re.p[i] = u.p[i - n];
}
return re;
}
int main(){
useless one(2,'x');
useless two = one;
useless four(one + two);
}

Assigning memory

I'm trying to assign memory por double *r[3]
Whenever I try this way it keep failing:
#include <cstdio>
int main(){
int N = 10;
double *r[3] = new double[N][3];
delete r;
return 0;
}
How is the correct way?
You need to assign blocks of memory to each cell your pointer points to.
double **r = new double* [N];
for(int i = 0; i < N; i++)
{
*(r + i) = new double[3];
delete [] *(r + i);
}
delete [] r;
Better is to use std::vector:
std::vector<std::vector<double>> r;
Use
double (*r)[3] = new double[N][3];
and
delete [] r;
Just use std::array
#include <array>
int main()
{
int N = 10;
typedef std::array<double,3> darray;
darray *r = new darray[N];
delete []r;
return 0;
}

Why am I getting *** glibc detected *** free(): invalid pointer error?

I am getting this error on my delete[] in my code below
string lcs_tree(string sig, string flow)
{
int l1, l2;
string getres;
l1 = sig.length()+1;
l2 = flow.length()+1;
char *x, *y;
x = new char [l1];
y = new char [l2];
x = (char*)sig.c_str();
y = (char*)flow.c_str();
lcs_length(x, y, l1, l2, getres);
delete[] x;
delete[] y;
return getres;
}
I'm trying to make the delete to free up memory because my program keeps getting killed when I don't free up memory after dynamically creating arrays. My delete works for this section of the code
void lcs_length(char *x,char *y, int l1, int l2, string& getres)
{
int m,n,i,j,**c;
c = new int *[l1];
for(int t = 0; t < l1; t++)
c[t] = new int [l2];
char **b;
b = new char *[l1];
for(int t = 0; t < l1; t++)
b[t] = new char [l2];
m=strlen(x);
n=strlen(y);
for(i=0;i<=m;i++)
c[i][0]=0;
for(i=0;i<=n;i++)
c[0][i]=0;
for(i=1;i<=m;i++)
for(j=1;j<=n;j++)
{
if(x[i-1]==y[j-1])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]='c'; //c stands for left upright cross
}
else if(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]='u'; //u stands for upright or above
}
else
{
c[i][j]=c[i][j-1];
b[i][j]='l'; //l stands for left
}
}
print_lcs(b,x,m,n,getres);
for(int t = 0; t < l1; t++)
delete[] c[t];
delete[] c;
for(int t = 0; t < l1; t++)
delete[] b[t];
delete[] b;
}
But when I use it in the first section I am getting the invalid pointer error. Why am I getting it there and not the second section?