Copy constractor with memory allocation and deallocation - c++

I have written following piece of code
#include<iostream>
#include<cstring>
using namespace std;
///Driver class
class driver
{
char *name;
int age;
public:
//Default contructor
driver(){}
//Constructor for initialize
driver(int a, char* n)
{
age = a;
int len = strlen(n);
//Allocate memory for name
name = new char[len];
strcpy(name, n);
}
//Copy constructor
driver(const driver &d)
{
name = new char[strlen(d.name)];
strcpy(name, d.name);
age = d.age;
}
void print()
{
cout<<"Name: "<<name<<endl;
cout<<"Age: "<<age<<endl;
}
~driver()
{
if(name != NULL)
{
delete name;
}
}
};
class automobile
{
driver drv;
char* make;
int year;
public:
automobile(driver d, char* m, int y)
{
drv = d;
int len = strlen(m);
make = new char[len];
strcpy(make, m);
year = y;
}
void print()
{
drv.print();
cout<<"Make: "<<make<<endl;
cout<<"Year: "<<year<<endl;
}
~automobile()
{
if(make!=NULL)
{
delete[] make;
}
}
};
int main()
{
driver d(15, "Jakir");
automobile a(d, "Toyta", 1980);
a.print();
return 0;
}
I have to use char* not string and allocate memory dynamically. But when I run the code, there occurs an error of memory leaks. I think it's due to the copy constructor and de-allocation memory of driver class. How to fix the error? Any suggestion is appreciated. Thanks in advance.

There is a lot of stuff wrong with this code, but I will list a few of the big ones.
As smentioned by others, you new char's need to be one bigger than they are.
You default constructor should set name to nullptr.
you have a memory handling error whenever you do an assignment, eg on this line: drv = d; because it calls the default operator=, which is incorrect in your case. Ther eis the Law of the Big Three which loosely states that whenever you need either a (non-trivial) copy constructor, copy assignment operator, or destructor, you'll most likely need to implement the others, too. You need to write an operator=!
Based on existing code, I would expect your operator= to look vaguely like this:
//assignment operator
const driver&operator=(const driver &rhs)
{
if (this==&rhs) return *this;
delete[] this->name;
this->name = new char[strlen(rhs.name)+1];
strcpy(this->name, rhs.name);
this->age = rhs.age;
return *this;
}
Do all that, and your core dump goes away.
PS Please, please just learn to use std::strings, new-ing char arrays and managing the memory yourself is a bad bad move.

name = new char[len+1]; not name = new char[len];
name = new char[strlen(d.name) + 1]; not name = new char[strlen(d.name)];
delete[] not delete
Need to define an assignment operator driver& operator=(const driver &d) in order to follow the rule of three.
Similar changes need to automobile.
However I don't see a memory leak, what makes you think you have one?

In main method you need to do like this,
driver* d = new driver(15, "Jakir");
automobile* a = new automobile (d, "Toyta", 1980);
a->print();
if ( a ) delete a ;
if ( d ) delete d ;
return 0 ;

Related

Copy And Assignment: How to Deep Copy? C++

I have two classes that are essentially string classes that look like this.
The first class holds a string as a member and the second class also holds a string plus an array of pointers for the 'MenuItem' class and also a tracker.
const int MAX_NO_OF_ITEMS = 10;
class Menu; // forward declaration
class MenuItem {
char* Menuitem;
//member functions
MenuItem();
...
~MenuItem();
friend Menu;
};
class Menu {
private:
char* m_Title;
MenuItem* m_MenuItems[MAX_NO_OF_ITEMS];
int m_menuTracker;
... //other functions not shown
}
I want to be able to deep copy one Menu object to another Menu object but the way I am doing it seems do be as if it were a shallow copy when it comes to copying over the 'm_MenuItems'. I know for sure that the 'm_Title' member is getting deep copied as I am creating a 'new' char* for it but the problem arises when I am trying to copy the source 'm_MenuItems' to the destination as they end up sharing the same memory. This causes problems because when the deconstructor is called, it is called twice on the same object, causing my program to crash.
Here is my copy and assignment code:
Menu& Menu::operator=(const Menu& src) {
if (this != &src && src.m_Title != nullptr) {
delete[] m_Title;
m_Title = nullptr;
m_Title = new char[strlen(src.m_Title) + 1];
strcpy(m_Title, src.m_Title);
//if current object has menuItems, then delete to make room for src.
for (int i = 0; i < m_menuTracker; i++) {
delete m_MenuItems[i];
this->m_MenuItems[i] = nullptr;
}
This following for-loop is where my problem arises...
if (src.m_MenuItems[0] != nullptr) {
for (int i = 0; i < src.m_menuTracker; i++) {
m_MenuItems[i] = src.m_MenuItems[i];
}
this->m_menuTracker = src.m_menuTracker;
}
else
this->m_menuTracker = 0;
}
else {
this->setEmpty();
}
return *this;
}
How am I supposed to allocate a new block of memory for the destination 'm_MenuItems'?

Dynamically allocated char array shows as uninitialized with constructor

When compiling this code, I get this warning:
Conditional jump or move depends on uninitialized value(s)
My set function is using a dynamic array and I wish to have it delete the dynamic space if it already exists.
The class:
class Name
{
char* m_name;
public:
Name();
Name(const char*);
~Name();
void set(const char*);
}
The constructor and setEmpty():
void Name::setEmpty()
{
m_name = nullptr;
}
Name::Name()
{
setEmpty();
}
The function:
void Name::set(const char* name)
{
if (name == nullptr || std::strlen(name) == 0)
{
setEmpty(); // <-- What my constructor has; sets 'm_name' to nullptr;
}
else
{
int length = std::strlen(name) + 1;
if (m_name != nullptr) // <-- gives warning because m_name is not initialized however it was created via constructor (?)
{
delete[] m_name;
}
m_name = new char[length]; // <-- No matter what I want to re-create the dynamic array
std::strcpy(m_name, name);
}
}
Main():
int main()
{
// constructors
Name s1("Sample");
Name s2, s3;
Name badData[] = {
Name ("Kappa"),
Name("Omega"),
Name(nullptr),
Name("", )
};
s1.set("Sample");
//...//
}
It's not terribly clear, but if your class has any constructors that don't call setEmpty(), possibly one of them does not initialise m_name. If that happens, a subsequent call of set() with a non-null pointer for which strlen() returns a non-zero value will test the value of m_name when it is uninitialised. You haven't shown how the constructor that accepts a const char * is defined, so it is possible that constructor is the culprit. – Peter 5 mins ago
This actually was the problem.
Solution:
Name::Name(const char* name)
{
setEmpty(); // <-- call safe state in all constructors
set(name, dob, power, level, super);
}
I didn't realize I needed to call either the function or the constructor that initializes values before I use my set function in the overloaded constructor.
Thank you Peter.

Why Initiate a pointer variable in member function of a class again?

this might a stupid question, but I'm finding it hard to understand why do we need to initiate the pointer variable into the class public member function again, even it is declared in the private section of the class.
This is the basic code of what I'm trying to ask.
class Human{
private:
std::string *name;
int *age;
public:
Human(std::string iname, int iage){
name = new std::string;
age = new int;
*name = iname;
*age = iage;
std::cout<<"Constructor Called \n \n";
}
void display(){
std::cout<<"My name is "<<*name<<" And my Age is "<<*age<<std::endl<<std::endl;
}
~Human(){
delete name;
delete age;
std::cout<<"Destructor Called \n \n";
}
};
int main(){
Human *noor = new Human("Noor", 10);
noor->display();
delete noor;
}
With the above code, the output is working just as expected, just if I comment the dynamic allocation of pointer on Human Constructor . i.e
Human(std::string iname, int iage){
// name = new std::string;
// age = new int;
*name = iname;
*age = iage;
std::cout<<"Constructor Called \n \n";
}
There is a close program warning on command prompt after successful compilation.
Alright, I understood the curve.
It is as in private section the pointer is just been declared and no memory is being allocated to the pointer. So we did allocate the memory for the pointer in constructor.
alternatively, we can directly allocate the memory in the private section as well.
i.e:
class Human{
private:
std::string *name = new std::string;
int *age = new int;
.....
.....
};
Thanks Everyone who responded.

copying constructor and operator= (multiple arrays...)

i have to create a copy constructor and assignment operator= for Reg class.
But i have theese complicated structures and don't know how to copy it correctly.
So, Question is, how can i create copy constructor for class Reg - shallow copy?
Another question is, how should operator= look like - it should be a deep copy of Reg
struct TMoves
{
const char* ddate;
const char* sstreet;
const char* ccity;
public:
~TMoves()
{
delete [] ccity;
delete [] ddate;
delete [] sstreet;
}
};
struct TData
{
int stackmult;
const char* iid;
const char* nname;
const char* ssurname;
int pocet;
TMoves** moves;
public:
TData()
{
stackmult=1;
}
~TData()
{
delete [] iid;
delete [] nname;
delete [] ssurname;
for(int i=0;i<pocet;i++)
{
delete moves[i];
}
delete [] moves;
}
};
class Reg
{
public:
Reg ();
Reg (const Regr&);
~Reg();
Reg& operator= (const Reg &);
bool Add (const char* id, const char* name, const char* surname, const char* date, const char* street, const char* city );
bool Resettle ( const char* id, const char* date, const char* street, const char* city );
private:
static const int MAX=1000; //default lenght of pole
TData **pole;
int counter; // pole lenght counter - not important now
int multiplier; // used for realocating pole
};
Reg::Reg()
{
counter=0;
multiplier=1;
pole=new TData*[multiplier*MAX];
}
Reg::Reg(const Reg& out)
{
//... how?
}
Reg::Reg &operator= (const Reg& copy)
{
//... how?
}
in method Add - here i find correct place(misto) where should i place id - using binary search
int misto=counter;
pole[misto]=new TData;
char *temp = new char[12];
strcpy(temp, id);
pole[misto]->iid = temp;
temp = new char[strlen(name)+1];
strcpy(temp, name);
pole[misto]->nname = temp;
temp = new char[strlen(surname)+1];
strcpy(temp, surname);
pole[misto]->ssurname = temp;
pole[misto]->moves=new TMoves*[STAT];
pole[misto]->moves[0]=new TMoves;
temp = new char[strlen(city)+1];
strcpy(temp,city);
pole[misto]->moves[0]->ccity= temp;
temp = new char[strlen(date)+1];
strcpy(temp,date);
pole[misto]->moves[0]->ddate= temp;
temp = new char[strlen(street)+1];
strcpy(temp,street);
pole[misto]->moves[0]->sstreet= temp;
in method Ressetle - i find id - i have to find place where shall i add another info(city,street,date) and i create to it new TMoves:
pole[misto]->moves[misto2]=new TMoves;
char *temp = new char[strlen(city)+1];
strcpy(temp,city);
pole[misto]->moves[misto2]->ccity= temp;
temp = new char[strlen(date)+1];
strcpy(temp,date);
pole[misto]->moves[misto2]->ddate= temp;
temp = new char[strlen(street)+1];
strcpy(temp,street);
pole[misto]->moves[misto2]->sstreet= temp;
This topic may be confusing, but my code is soo long and i am facing "only" to theese two problems with copying. Thank you for your time and replies.
Don't give different kinds of semantics to copy constructor and copy assignment operator.
By default both should give a free-standing copy.
The best implementation of a copy constructor is to rely on copy construction of members and just use the compiler-generated one. To do this, use std::string instead of char*, and use std::vector for other arrays. It's that simple.
For the homework situation where you have been explicitly instructed to not use string and vector, define your own such classes.
Keep to the maxim that each class manages at most one resource, such as a dynamically allocated thingy.

Destructor causing segmentation fault

I have implemented a class string, similar to std::string one.
I have a problem when the destructor is called: the field length has the length of the characters allocated in field.
This is the class:
class indexException:public std::exception
{
public:
virtual const char* what()
{
return "Index is either too long, or negative";
}
};
class string
{
public:
static const unsigned int length_max=100;
string(const char* field=NULL)
{
if(field!=NULL)
{
const unsigned int length=strlen(field);
this->field=new char[length+1];
this->length=length;
for(unsigned int i=0;i<=length;i++)
this->field[i]=field[i];
}
else
{
this->field=NULL;
length=0;
}
}
string(string& str)
{
string(str.field);
}
~string()
{
if(length>0)
delete field;
}
char& operator[] (int i) const throw()
{
try
{
if(i<0 || i>=(int)length)
throw indexException();
}
catch(indexException& e)
{
std::cerr << e.what() << std::endl;
}
return field[i];
}
string& operator=(const char* field)
{
const unsigned int length=strlen(field);
if(this->length>0)
delete this->field;
this->field=new char[length];
this->length=length;
for(unsigned int i=0;i<length;i++)
this->field[i]=field[i];
return *this;
}
string& operator= (const string& str)
{
if(this!=&str)
*this=str.field;
return *this;
}
operator char* ()
{
return field;
}
friend std::ostream& operator<< (std::ostream& out, string& str);
friend std::istream& operator>> (std::istream& in, string& str);
public:
unsigned int length;
char* field;
};
std::ostream& operator<<(std::ostream& out, string& str)
{
out << str.field;
return out;
}
std::istream& operator>> (std::istream& in, string& str)
{
char temp[string::length_max];
in >> temp;
str=temp;
return in;
}
If I use the assignment operator, this doesn't cause a segmentation fault.
But it undirectly cause it.
I explain how:
int main(int argc,char** argv)
{
string str="hi";
string str2=str;
return 0;
}
Putting a breakpoint into the assignment operator overloading, I realized that the assigment operator doesn't cause segmentation fault.
The problem is after, when exiting from main.
If I remove the destructor I don't get this segmentation fault, but I would know why I get this problem.
Edit: I have understood where's the problem.
I followed your suggestions but it still goes to segmentation fault.
But now it doesn't crash anymore on the destructor method, but on the assignment operator overloading:
string& operator=(const char* field)
{
unsigned int length=0;
if(field!=NULL)
length=strlen(field);
else
field="";
if(this->length>0)
delete[] this->field;
this->field=new char[length+1];
this->length=length;
strcpy(this->field,field);
return *this;
}
The problem is when I delete this->field, the debugger stops there.
An example of segmentation fault:
string str("hi");
string str2=str;
This causes segmentation fault.I suppone it's because str2 is not initialized, and length has an undefined value.
If I instead do this:
string str("hi");
string str2;
str2=str;
There isn't any segmentation fault.Why?
I thought that calling :
string str2;
Was also calling the constructor, or is that the "=" operator has the precedence?
How to solve this?
PS: I also changed other things,like the copy constructor.
Full code is here:
http://pastebin.com/ubRgaVr8
Solved: I changed the copy constructor as suggested in the accepted reply:
string(const string& str)
{
length=str.length;
field=new char[str.length+1];
memcpy(field,str.field,length+1);
}
Your copy constructor doesn't initialise the object.
string(string& str)
{
string(str.field); // Does nothing
}
string(str.field)creates an unnamed stringand immediately throws it away.
It does not initialise this object using a different constructor.
Since your object now consists only of randomness, bad things will happen when you try to destroy it.
To make sure things are initialised, make a private member function
void initializeFromChars(const char* cString);
that does the work and use it in your constructors and assignment operator.
EDIT: Scrapped my previous answer, as it was incorrect.
The problem appears to be the copy constructor, you are passing the field from the source instance as though it is merely another null terminated char*, but it isn't.
You don't copy the null character at the end during the char* assignment invoked by the previous statement, you use an internal length field instead, and copy only that many bytes.
so your copy constructor should be:
string(string& str)
{
length = str.length;
field = new char[length];
memcpy(field, str.field, length);
}
or, if you want to preserve compatibility with null terminated functions, and you have ensured that the null is kept for all other assignments/constructors, etc:
string(string& str)
{
length = str.length;
field = new char[length + 1];
memcpy(field, str.field, length + 1);
}
In fact, the mixing null terminated, and specified length strings so much throughout your class appears to be confusing you.
I would create an internal, private, single disposal method, and an array of methods to set various source types, and have the constructors, assignment operators, and destructors use those instead.
That way you only have a single places where any given operation occurs, rather than juggling many minor variations on the same functionality. For example:
private:
void internalSet(const char *source) {
if (source == NULL) {
length = 0;
field = NULL;
}else{
length = strlen(source);
field = new char[length];
memcpy(field, source, length);
}
}
void internalSet(const string &source) {
length = source.length;
if (length > 0) {
field = new char[length];
memcpy(field, source.field, length);
}else{
field = NULL;
}
}
void internalDispose() {
delete[] field;
}
public:
string() : field(NULL), length(0) {}
string(const string& source) { internalSet(source); }
string(const char *source) { internalSet(source); }
~string() { internalDispose(); }
string& operator=(const char *source) {
internalDispose();
internalSet(source);
return *this;
}
string& operator=(const string &source) {
internalDispose();
internalSet(source);
return *this;
}
void clear() {
internalDispose();
length = 0;
}
Your destructor uses delete, when it should use delete[].
Once you allocate memory with
field = new char[length+1];
You should delete it with:
delete [] field;
And you're not checking whether your allocation was successful.
Another thing considered good practice is setting field to NULL after delete so it won't get deleted twice (if you start delivering classes) for example:
~string(){
delete [] field;
// field = NULL;
}
Note: according to Dietmar Kühl setting field=NULL isn't good practice (take a look at the comments) and choose your way, here's question specifically about this: Is it worth setting pointers to NULL in a destructor? .
Note 2: KerrekSB pointed out that delete [] field will do nothing if pointer is NULL and whole condition is unnecessary.
Than in string& operator=(const char* field) you probably want to allocate length + 1 and iterate to it too (to include terminating NULL).
And I don't like your string& operator= (const string& str), you have cached info on length of string and you're using strlen() and than manual copy char by char.
Your copy constructor also looks bad... You should "copy" manual allocation and copy byte by byte to it. Or rather build protected function like fromCString(const char *) and use it in both constructors and assign operators.
If those doesn't help ask in comment for more help.