Destructor causing segmentation fault - c++

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.

Related

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.

Setting char* properties of a class

I have 10 char* properties of my class called Car,what is the best way to write the setters of these 10 char* properties? One way is to directly set the value in it :
void Car<T>::setKey(const char* toCopyKey)
{
delete[] key;
int length=strlen(toCopyKey);
key=new char[length+1];
strcpy(key,toCopyKey);
}
and do this 10 times ,other solution I thought of , is to make a function that creates a copy of the passed char* and then assigns it in the setter :
char* Car<T>::copyString(const char* s)
{
int length=strlen(s);
char* property=new char[length+1];
strcpy(property,s);
return property;
}
and use the copyString method in every setter like this :
void Car<T>::setModel(const char* toCopyModel)
{
delete[] model;
model=copyString(toCopyModel);
}
But I was wondering if this second solution is correct and if there is a better way to do this copying?I cannot use std::string and vector.
I guess this is an assignment of some C++ course or tutorial, because otherwise I would recommend to question the whole design.
In general, I would learn as early as possible to not do manual memory management at all and use C++ standard library smart pointers. This relieves you from the burden to write destructors, copy|move-assignment and copy|move constructors.
In your example, you could use std::unique_ptr<char[]> to hold the string data. This is also exception safe and prevents memory leaks. Creation of the unique_ptr<char[]> objects can be centralized in a helper method.
class Car {
private:
std::unique_ptr<char[]> model;
std::unique_ptr<char[]> key;
static std::unique_ptr<char[]> copyString(char const* prop) {
auto const len = std::strlen(prop);
auto p = std::make_unique<char[]>(len+1);
std::copy(prop, prop + len, p.get());
p[len] = '\0';
return p;
}
public:
void setModel(char const* newModel) {
model = copyString(newModel);
}
void setKey(char const* k) {
key = copyString(k);
}
char const* getModel() const {
return model.get();
}
};
If you don't know them, I would recommend to read about the rule of zero.
You can combine your two methods by using a reference parameter:
static void Car<T>::setStringProp(char *&prop, const char *toCopyString) {
delete[] prop;
prop = new char[strlen(toCopyString)+1];
strcpy(prop, toCopyString);
}
void Car<T>::setModel(const char *toCopyModel) {
setStringProp(model, toCopyModel);
}
And make sure that your constructor initializes all the properties to NULL before calling the setters, because delete[] prop requires that it be an initialized pointer.
Car<T>::Car<T>(const char *model, const char *key, ...): model(nullptr), key(nullptr), ... {
setModel(model);
setKey(key);
...
}

Why initializing a second object does modify my first object?

I have a class IStream2:
class IStream2 {
private:
char* fn;
public:
IStream2(char* filename);
char* get_filename();
};
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
char * IStream2::get_filename() {
return fn;
}
And here is the main code:
vector<IStream2> istreams;
char fn[] = "file1.txt";
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
char fn2[] = "file2.txt";
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
It prints file2.txt but I expected file1.txt.
I know that I should use string but I would like to resolve this problem.
IStream2::IStream2(char *filename) {
strcpy(fn, filename);
}
Allocates no storage for fn. strcpy(fn, filename); invokes undefined behaviour writing into whatever storage fn points at, and after that all bets are off. The program could do anything.
The right answer is to use std::string
class IStream2 {
private:
std::string fn;
public:
IStream2(const char* filename); // note const. if not modifying a passed rference,
// mark it const. The compiler can make optimizations
// and can catch mistakes for you
// also the function can now receive string literals
const char* get_filename(); // another const this is because a string won't
// easily give you a non const pointer
}; <-- note the added ;
IStream2::IStream2(const char *filename): fn(filename) {
}
const char * IStream2::get_filename() {
return fn.c_str(); // get the char array from the string
}
But I suspect this is an exercise in writing C with Classes, so back into the stone ages we go. This is a LOT more work because we have to manage all of the memory ourselves. For example, We need to observe the Rule of Three. What is The Rule of Three?
Sigh.
class IStream2 {
private:
char* fn;
public:
IStream2(const char* filename); // note const char *
~IStream2(); // need destructor to clean up fn. This means we need to
// comply with the Rule of Three
IStream2(const IStream2 & src); // copy constructor
IStream2 & operator=(IStream2 src); // assignment operator
char* get_filename(); // Note: by returning a non const pointer here we
// allow the caller to tamper with the contents of
// fn and even delete it. This defeats the point
// of declaring fn private, so avoid doing this.
};
IStream2::IStream2(const char *filename) {
fn = new char[strlen(filename) +1]; // allocate storage.
// The +1 is to hold the string's NULL terminator
strcpy(fn, filename);
}
// implement copy constructor
IStream2::IStream2(const IStream2 & src) {
fn = new char[strlen(src.fn) +1];
strcpy(fn, src.fn);
}
// implement destructor
IStream2::~IStream2()
{
delete[] fn;
}
// implement assignment operator. Using Copy And Swap Idiom
IStream2 & IStream2::operator=(IStream2 src)
{
std::swap(fn, src.fn);
return *this;
}
char * IStream2::get_filename() {
return fn;
}
int main()
{
vector<IStream2> istreams;
const char* fn = "file1.txt"; // note const char *. string literals may be
// read-only memory and can't be changed
IStream2 reader2 = IStream2(fn);
istreams.push_back(reader2);
const char* fn2 = "file2.txt"; // and again const char *
IStream2 reader3 = IStream2(fn2);
istreams.push_back(reader3);
cout << istreams[0].get_filename() << endl;
return 0;
}
Since we are wresting with dinosaurs, I won't bother with the Rule of Five and move operations, but see how much more annoying it is to have to do this the wrong way?
More on Copy And Swap Idiom

Access violation reading location 0x00000000 cstrings

From reading other stackoverflow questions I am aware that this error means I am trying to dereference a null pointer. However, I cannot figure out where my code is dereferencing a null pointer. I am trying to set a char* (cstring) to a non-null value, but I get an access violation error. Here is the code:
void Data::setName(char const * const name)
{
if (this->name)
delete[] this->name;
this->name = new char[strlen(name) + 1]; // This is where my code breaks in debug mode
strcpy(this->name, name);
}
name is a char* variable that gets initialized to null. setName is being called by an overloaded assignment operator:
Data& Data::operator=(const Data& data2)
{
//if it is a self copy, don't do anything
if (this == &data2)
return *this;
else
{
setName(data2.name); // Here is the call to setName
return *this;
}
}
P.S. For the love of god please don't tell me I shouldn't be using cstrings! I know std::string is better, but this is for a homework assignment that requires cstrings.
If this is the line the code breaks:
this->name = new char[strlen(name) + 1];
then name must be a null pointer, since nothing else is being dereferenced. name is being dereferenced inside the strlen function. Just print the variable value in your debugger and you will be sure.
Also, using same name of variable in the setter like this:
struct A
{
void set(int a){this->a = a;}
int a;
};
is not a good practice. Just use:
struct A
{
void set(int na){a = na;}
int a;
};
or
struct A
{
void set(int a){a_ = a;}
int a_;
};

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.