Reputation: 423
noob here. I'm doing an exercise from a book and the compiler reports no errors, but the program crashes when I try to run it.
I'm trying to run a little program exercising the different methods of the Cow class. It explicitly has: a constructor, a default constructor, a copy constructor, a destructor, an overloaded assignment operator, and a method to show its contents.
I'll put the whole project:
Class specification:
//cow.h -- For project Exercise 12.1.cbp
class Cow
{
char name[20]; // memory is allocated in the stack
char *hobby;
double weight;
public:
Cow();
Cow(const char *nm, const char *ho, double wt);
Cow(const Cow &c);
~Cow();
Cow & operator=(const Cow &c);
void ShowCow() const; // display all cow data
};
Methods implementation:
// cow.cpp -- Cow class methods implementation (compile with main.cpp)
#include <cstring>
#include <iostream>
#include "cow.h"
Cow::Cow() // default destructor
{
strcpy(name, "empty");
hobby = new char[6]; // makes it compatible with delete[]
strcpy(hobby, "empty");
weight = 0.0;
}
Cow::Cow(const char *nm, const char *ho, double wt)
{
strcpy(name, nm); // name = nm; is wrong, it copies the address of the argument pointer (swallow copying)
/*if (name[20] != '\0') // if it's not a string, make it a string (in case nm is larger than 20)
name[20] = '\0';*/
hobby = new char[strlen(ho) + 1]; // allocates the needed memory to hold the argument string
strcpy(hobby, ho); // copies the pointed-to data from the argument pointer to the class pointer
weight = wt;
}
Cow::Cow(const Cow &c) // copy constructor
{
strcpy(name, c.name); // copies the value to the desired address
char *temp = hobby; // stores the address of the memory previously allocated with new
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby); // copies the value to the new address
delete[] temp; // deletes the previously new allocated memory
weight = c.weight;
}
Cow::~Cow()
{
delete[] hobby;
}
Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
strcpy(name, c.name);
char *temp = hobby;
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby);
delete[] temp;
weight = c.weight;
return *this;
}
void Cow::ShowCow() const
{
std::cout << "Name: " << name << '\n';
std::cout << "Hobby: " << hobby << '\n';
std::cout << "Weight: " << weight << "\n\n";
}
Client:
// main.cpp -- Exercising the Cow class (compile with cow.cpp)
#include "cow.h"
#include <iostream>
int main()
{
using std::cout;
using std::cin;
Cow subject1; // default constructor
Cow subject2("Maria", "Reading", 120); // non-default constructor
Cow subject3("Lula", "Cinema", 135);
subject1 = subject3; // overloaded assignment operator
Cow subject4 = subject2; // copy constructor
subject1.ShowCow();
subject2.ShowCow();
subject3.ShowCow();
subject4.ShowCow();
cin.get();
return 0;
}
I was hiding some parts of the code to locate the possible problem and it seems the progam doesn't like this two lines:
subject1 = subject3;
Cow subject4 = subject2
And in particular, in the overloaded assignment operator and the copy constructor, if I hide the delete[] temp
line, the program doesn't crash.
I'm total noob and probably is something stupid but I can't see what I'm doing wrong in these definitions.
Any help?
Upvotes: 1
Views: 6397
Reputation: 55897
Cow::Cow(const Cow &c) // copy constructor
{
strcpy(name, c.name); // copies the value to the desired address
char *temp = hobby; // stores the address of the memory previously allocated with new
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby); // copies the value to the new address
delete[] temp; // deletes the previously new allocated memory
weight = c.weight;
}
It's the copy c-tor. There is no previously allocated members. this->hobby
points to random garbage. So when you delete[] temp
(i.e. this->hobby
before the new assignment), you get UB.
Cow & Cow::operator=(const Cow &c) // overloaded assignment operator
{
strcpy(name, c.name);
char *temp = hobby;
hobby = new char[strlen(c.hobby) + 1];
strcpy(hobby, c.hobby);
delete[] temp;
hobby = name;
weight = c.weight;
return *this;
}
hobby = name
is incorrect, as it causes a memory leak + destructor will try to delete an object that was not allocated with operator new[]
.
Upvotes: 3
Reputation: 96281
@ForEveR Already noted that your copy constructor is deleting memory that was never allocated.
But I'm going to argue that the entire exercise is flawed and is teaching C with classes, NOT C++. If you used string all your problems would go away because you wouldn't have to manage resources directly. This eliminates the need for you to write a destructor or copy assignment/constructor entirely. For example:
class Cow
{
std::string name;
std::string hobby;
double weight;
public:
Cow();
Cow(const std::string& nm, const std::string& ho, double wt);
void ShowCow() const; // display all cow data
};
Upvotes: 0