I am trying to create a member function which print out the array that I control, but I am running into Seg fault. Any help would be really useful!
Here is my header file, all the code in there work except the last member function.
#include <iostream>
#include <assert.h>
using namespace std;
#ifndef _ARRAY_H
#define _ARRAY_H
template<class T>
class Array{
private:
T *a;
int length;
public:
// constructor
Array (int len){
length = len;
a = new T[length];
for (int i = 0; i < len; i++){
a[i]=0;
}
}
// destructor
~Array()
{delete[] a;}
// operator overload
T& operator [](int i){
assert (i>=0 && i < length);
return a[i];
}
// operator overload
Array<T>& operator=(Array<T> &b){
if (a !=nullptr) delete[] a;
a = b.a;
b.a = nullptr;
length = b.length;
return *this;
}
//get the length of the array
int arraylength(){
return length;
}
//------------------This below is where I am having issue --------//
//print out the array
Array<T> printarray(){
for (int i = 0; i < length; i++){
cout << a[i];
}
}
};
int main();
#endif
This is my main file
#include <iostream>
#include "../include/array.h"
using namespace std;
int main(){
// initialize array
Array <int> a(5);
Array <int> b(5);
// put stuff into array
for (int i = 0; i< a.arraylength(); i++){
a[i] = i;
}
// set b = a using operator overload
b = a;
// print out the result b array
for (int i = 0; i < b.arraylength(); i++){
cout << b[i] << endl;
}
a.printarray();
return 0;
}
Again. Thank you for the help, I am quite new to C++ and mostly self taught.
In this statement
b = a;
you have called operator= in which a pointer of a object was set to nullptr, but in printArray you don't check if a is not null, so you are accesing data for null pointer, it is undefined behaviour. Add the condition to check if array is not empty:
void printarray(){
if (!a) return; // <- array is empty
for (int i = 0; i < length; i++){
cout << a[i];
}
}
Secondly, return type of printArray should be void, you don't return any value in this function.
You should fix printarray by changing the return type to void and making it a const member function.
void printarray() const {
for (int i = 0; i < length; i++){
cout << a[i];
}
}
However, that is not the main problem in your code. The main problem is that you are not following the The Rule of Three.
You don't have copy constructor.
You have a copy assignment operator but it is not implemented properly.
The line
b = a;
causes problems downstream that can be fixed by following The Rule of Three.
Here's an implementation of the copy assignment operator function that should work.
// Make the RHS of the operator a const object.
Array<T>& operator=(Array<T> const& b)
{
// Prevent self assignment.
// Do the real assignment only when the objects are different.
if ( this != &b )
{
if (a != nullptr)
{
delete[] a;
a = nullptr;
}
// This is not appropriate.
// a = b.a;
// b.a = nullptr;
// b needs to be left untouched.
// Memory needs to be allocated for this->a.
length = b.length;
if ( length > 0 )
{
a = new T[length];
// Copy values from b to this.
for (int i = 0; i < length; ++i )
{
a[i] = b.a[i];
}
}
}
return *this;
}
Please note that you should implement the copy constructor also, and then use the copy swap idiam to implment the assignment operator.
Very relevant: What is the copy-and-swap idiom?
Related
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.
I want to write a program that can use a dynamic array.
A size is to be passed via the constructor and as soon as this size is reached, a new array is generated in which the previous values are copied into it.
For this, I overloaded the [] operator. The program seems to work at first glance.
But after I tried to implement an array with the size 100 and to save 20000 elements here, different numbers are output.
At the first run, more than 7000 numbers were displayed. After another run over 1800. However, never the desired 20000.
What could be the reason for this?
#include <iostream>
using namespace std;
template<class T>
class Container{
public:
T *dynamicArray;
private:
T *newArray;
int size;
public:
Container(int size){
this->size=size;
dynamicArray=new T[size];
}
T operator[] (unsigned long index){
if(index>size-1){
newArray=new T[size+(index-size)];
T i;
for(i=0; i<(size+(index-size)); i++){
newArray[i]=dynamicArray[i];
}
delete[] dynamicArray;
dynamicArray=newArray;
delete[] newArray;
}
return dynamicArray[index];
}
};
int main()
{
Container <int> dArray(100);
for(int i=1; i<20000; i++){
dArray.dynamicArray[i]=i;
cout << dArray.dynamicArray[i] << "\n";
}
return 0;
}
Thank you!
first , this code didn't call the overloaded [] operator function , its just using default operator [] of type T array , and it never allocate any memory , you can output at allocate memory position
dArray.dynamischesArray[i]=i;
cout << dArray.dynamischesArray[i] << "\n";
and there it some error logic in the overloaded [] operator function
T operator[] (unsigned long index){
if(index>size-1){
neuesArray=new T[size+(index-size)];
T i;
for(i=0; i<(size+(index-size)); i++){
neuesArray[i]=dynamischesArray[i];
}
delete[] dynamischesArray;
dynamischesArray=neuesArray;
//delete[] neuesArray; cannot deleted ,course error
size = index + 1; //keep size sync real size
}
return dynamischesArray[index];
}
this is modified code can be run correct :
#include <iostream>
#include <string>
using namespace std;
template<class T>
class Container {
public:
T *dynamischesArray;
private:
T *neuesArray;
int size;
public:
Container(int size) {
this->size = size;
dynamischesArray = new T[size];
}
T& operator[] (unsigned long index) {
if (index > size - 1) {
cout << "allocate :" << index<<"\n";
neuesArray = new T[index+1];
unsigned long i;
for (i = 0; i < size; i++) {
neuesArray[i] = dynamischesArray[i];
}
delete[] dynamischesArray;
dynamischesArray = neuesArray;
//delete[] neuesArray;
size = index+1;
}
T&ret = dynamischesArray[index];
//return dynamischesArray[index];
return ret;
}
};
int main()
{
Container <int> dArray(100);
for (int i = 1; i < 20000; i++) {
dArray[i] = i;
cout <<"i="<<i<<" "<< dArray[i] << "\n";
//dArray.dynamischesArray[i] = i;
//cout << dArray.dynamischesArray[i] << "\n";
}
return 0;
}
this is result
This is simple program that is supposed to handle a dynamic array of numbers and then to filter out the elements that are even and put them into a new array and then print both arrays on the screen.
This is the header file:
#pragma once
namespace filter
{
class Array
{
double *arr;
int n;
public:
Array();
Array(int);
Array(const Array&);
Array(Array&&);
void PutIn();
void PrintOut() const;
Array isEven();
Array filter(const std::function<bool(int)>&) const;
~Array();
};
}
Then, this is the implementation of functions:
#include <iostream>
#include <functional>
#include "Array.h";
using namespace filter;
using namespace std;
Array::Array() :arr(nullptr), n(0)
{ }
Array::Array(int n)
{
this->n = n;
arr = new double[n];
}
Array::Array(const Array &a1)
{
n = a1.n;
arr = new double[n];
for (int i = 0; i < n; i++)
arr[i] = a1.arr[i];
}
Array::Array(Array &&a1)
{
n = a1.n;
for (int i = 0; i < n; i++)
arr[i] = a1.arr[i];
a1.n = 0;
a1.arr = nullptr;
}
void Array::PutIn()
{
cout << "Insert elements:\n";
for (int i = 0; i < n; i++)
cin >> arr[i];
}
void Array::PrintOut() const
{
cout << "\nYour array is :\n";
for (int i = 0; i < n; i++)
cout << arr[i] << "\t";
}
Array Array::isEven()
{
return filter([](int x) { return x % 2; });
}
Array Array::filter(const std::function<bool(int)> &f) const
{
int b = 0;
for (int i = 0; i < n; i++)
if (f(arr[i]) == 0)
b++;
Array temp(b);
b = 0;
for (int i = 0; i < n; i++)
if (f(arr[i]) == 0)
{
temp.arr[b] = arr[i];
b++;
}
return temp;
}
Array::~Array()
{
delete[]arr;
n = 0;
}
Finally, this is the source code:
#include <iostream>
#include <functional>
#include "Array.h"
using namespace filter;
using namespace std;
int main()
{
Array a(5);
a.PutIn();
Array b = a.isEven(); //WHY THIS LINE OF CODE INVOKES MOVE CONSTRUCTOR AND NOT COPY CONSTRUCTOR?
a.PrintOut();
b.PrintOut();
getchar();
getchar();
}
So, as you can see, this is relatively simple program that needs to handle an array with five elements in it entered by user and then to create a new array that consists of even elements of the first array. When i run this, it works fine, however, there is one little thing that i don't understand here.
If you look at the source code, notice the line where i left my comment, that is the line where move constructor is called, but i don't know why. That would mean that a.IsEven() is a RVALUE, since move constructor works with RVALUES, right? Can anyone explain me why this is rvalue and what is the correct way to understand this? Any help appreciated!
Your assumption that calling isEven invokes your move constructor is not in fact correct. Nor does it invoke your copy constructor. Instead, RVO ensures that the object returned is constructed directly at the calling site so neither is required.
Live Demo (which doesn't address any of the flaws in your code mentioned in the comments).
This is example from a text book. We are creating vector using templates. in main function we copy the predefined array into vectors. Finally, we multiply two vectors. Although program compiles nicely the program fails to execute. Whats wrong with the code.
#include <iostream>
const int size = 3;
template<class T>
class vector
{
T* v;
public:
vector()
{
v = new T[size];
for (int i = 0; i < size; i++){
v[i] = 0;
}
}
vector(const T* a)
{
for (int i = 0; i < size; i++){
v[i] = a[i];
}
}
T operator * (const vector& y)
{
T sum = 0;
for (int i = 0; i < size; i++){
sum += this->v[i] * y.v[i];
}
return sum;
}
};
int main()
{
int x[3] = { 1, 2, 3 };
int y[3] = { 4, 5, 6 };
vector<int> v1;
vector<int> v2;
v1 = x;
v2 = y;
int R = v1 * v2;
std::cout << R;
return 0;
}
First of all in this constructor
vector(T *a)
{
for(int i=0;i<size;i++){
v[i]= a[i];
}
}
you did not allocate the array pointed to by v. Pointer v is not initialized. So the constructor has undefined behaviour.
And another potential problem is that you did not define the copy assignment operator.
In these statements
v1 = x; v2 = y;
temporary objects of type vector are created and after the assignment they will be deleted. Thus the new created objects will have invalid pointer v.
You have to define at least copy constructor, copy assignment operator and destructor.
C++ Copy Constructor and Assignment Operator Define
Could anybody help me correct the following copy constructor and assignment operator?
as you see, assignment operator seems to work well; I ran it and it works.
Do I define the assignment operator correct? Please let me know.
This crashes with the copy constructor...
How can I fix the copy constructor?
Please help me.
#include <iostream>
using namespace std;
class IntP
{
private:
unsigned int* counts;
unsigned int numP;
unsigned int size;
public:
IntP(); // Default Constructor
IntP(int n); // Constructor
IntP(const IntP& a); // Copy Constructor
IntP& operator= (const IntP& a); // Assignment Operator
~IntP(); // Destructor
void printIntP() const;
};
IntP::IntP() // Default Constructor
{
counts = new unsigned int[101] (); // initialize array of size 101 to all 0s
numP = 0;
size = 101;
}
IntP::IntP(int n) // Constructor
{
counts = new unsigned int[n+1] (); // initialize array of size n+1 to all 0s
counts[n] = 1;
numP = 1;
size = n+1;
}
// ????????????
//
IntP::IntP(const IntP& a) // Copy Constructor
{
this->size = a.size;
this->numP = a.numP;
for (int i=0; i < (int) this->size; i++)
this->counts[i] = a.counts[i];
}
// ???????????
// Correct Implementation?
// without delete operator, we have memory leak? but it compiles without error???
IntP& IntP::operator= (const IntP& a) // Assignment Operator
{
if (this != &a)
{
delete [] counts; // Get rid of old counts
size = a.size;
numP = a.numP;
counts = new unsigned int[size+1];
counts[size] = 1;
for (int i=0; i < (int) this->size; i++)
counts[i] = a.counts[i];
}
return *this;
}
IntP::~IntP() { delete [] counts; }
void IntP::printIntP() const
{
cout << "The size of array is " << this->size << endl;
cout << "The numP variable becomes " << this->numP << endl;
int i = 0;
while ( i != (int) this->size )
{
cout << counts[i];
if ( i != (int) this->size-1 ) cout << " , ";
i++;
}
cout << endl << endl;
}
int main (void)
{
IntP ip2(200);
IntP ip3;
ip3 = ip2;
IntP ip1(100);
cout << "Print out ip1 object after IntP ip1(100); " << endl;
ip1.printIntP();
IntP ip4(ip1);
cout << "Print out ip4 object after IntP ip4(ip1); " << endl;
ip4.printIntP();
system("pause"); return 0;
}
Your code crashes because of you don't allocate memory for counts in copy constructor.
IntP::IntP(const IntP& a) // Copy Constructor
{
//counts = new unsigned int[a.size] (); // Add this to allocate memory for counts
this->size = a.size;
this->numP = a.numP;
for (int i=0; i < (int) this->size; i++)
this->counts[i] = a.counts[i]; //counts is unitialized
}