Your copy constructor is declared incorrectly. It is taking a DSString
object as input, but it needs to take a Classifier
object instead.
Also, your default constructor is not initializing the words
member at all, which causes the rest of the code to have undefined behavior whenever it tries to act on the member.
Also, there is no need for your copy assignment operator to allocate a completely new std::map
, it should just copy the data from the source std::map
to the existing std::map
. std::map
s own copy assignment operator will free the old data and copy the source data for you.
A proper Rule-of-3 implementation would look more like this:
#include <map>
class Classifier {
private:
using WordMap = std::map<DSString, std::map<char, float>>;
WordMap *words;
public:
Classifier();
Classifier(const Classifier& objToCopy); // Copy Constructor
~Classifier(); // Destructor
Classifier &operator=(const Classifier& objToCopy); // Copy Assignment Overload
};
#include "Classifier.h"
Classifier::Classifier() {
words = new WordMap();
}
Classifier::Classifier(const Classifier& objToCopy) {
words = new WordMap(*objToCopy.words);
}
Classifier::~Classifier() {
delete words;
}
Classifier& Classifier::operator=(const Classifier& objToCopy) {
if (this != &objToCopy) {
*words = *objToCopy.words;
}
return *this;
}
In C++11 and later, you should implement the Rule-of-5 as well, by adding a move constructor and move assignment operator, eg:
#include <map>
class Classifier {
private:
using WordMap = std::map<DSString, std::map<char, float>>;
WordMap *words;
public:
Classifier();
Classifier(const Classifier& objToCopy); // Copy Constructor
Classifier(Classifier&& objToMove); // Move Constructor
~Classifier(); // Destructor
Classifier &operator=(const Classifier& objToCopy); // Copy Assignment Overload
Classifier &operator=(Classifier&& objToMove); // Move Assignment Overload
};
#include "Classifier.h"
#include <utility>
Classifier::Classifier() {
words = new WordMap();
}
Classifier::Classifier(const Classifier& objToCopy) {
words = new WordMap(*objToCopy.words);
}
Classifier::Classifier(Classifier&& objToMove) {
words = new WordMap(std::move(*objToMove.words));
}
Classifier::~Classifier() {
delete words;
}
Classifier& Classifier::operator=(const Classifier& objToCopy) {
if (this != &objToCopy) {
*words = *objToCopy.words;
}
return *this;
}
Classifier& Classifier::operator=(Classifier&& objToMove) {
*words = std::move(*objToMove.words);
return *this;
}
Alternatively:
#include <map>
class Classifier {
private:
using WordMap = std::map<DSString, std::map<char, float>>;
WordMap *words;
public:
Classifier();
Classifier(const Classifier& objToCopy); // Copy Constructor
Classifier(Classifier&& objToMove); // Move Constructor
~Classifier(); // Destructor
Classifier &operator=(const Classifier& objToCopy); // Copy Assignment Overload
Classifier &operator=(Classifier&& objToMove); // Move Assignment Overload
void swap(Classifier& objToSwap);
};
#include "Classifier.h"
#include <utility>
Classifier::Classifier() {
words = nullptr;
}
Classifier::Classifier(const Classifier& objToCopy) : Classifier() {
if (objToCopy.words)
words = new WordMap(*objToCopy.words);
}
Classifier::Classifier(Classifier&& objToMove) : Classifier() {
objToMove.swap(*this);
}
Classifier::~Classifier() {
delete words;
}
Classifier& Classifier::operator=(const Classifier& objToCopy) {
if (this != &objToCopy) {
Classifier(objToCopy).swap(*this);
}
return *this;
}
Classifier& Classifier::operator=(Classifier&& objToMove) {
Classifier(std::move(objToCopy)).swap(*this);
return *this;
}
void Classifier::swap(Classifier& objToSwap) {
std::swap(words, objToSwap.words);
}
That being said, since std::map
already implements the Rule-of-3/5 for its own data, you don't need to use it dynamically at all. You should strive to implement the Rule-of-0 instead, by simply getting rid of the pointer altogether and letting the compiler-generated constructors/operators invoke the corresponding methods of a std::map
object for you, eg:
#include <map>
class Classifier {
private:
std::map<DSString, std::map<char, float>> words;
public:
// everything you need is auto-generated for you!
// a generated default constructor will default-construct the map...
// a generated copy constructor will copy the map...
// a generated move constructor will move the map...
// a generated destructor will destroy the map...
// a generated copy assignment will copy the map...
// a generated move assignment will move the map...
};
See how much simpler that is? :-)