提问人:user83975 提问时间:3/6/2023 更新时间:3/6/2023 访问量:94
用 C++ 编写 2D 地图的三法则
Writing the Rule of Three for a 2D map in C++
问:
我正在制作一个程序来确定一条推文是快乐还是悲伤,我想我把推文标记化,然后创建一个地图,将这个词存储为键,它总共使用了多少次,以及它在快乐的推文和悲伤的推文中使用了多少次。
我认为这是一个很好的方法,虽然可能有更好的选择,但我不太明白如何为我想创建的地图编写三法则。Classifier 对象将是用于对推文的情绪进行分类的对象,下面是 CLassifier.h 文件,不包括用于训练数据的其他方法(DSString 对象是一个字符数组)
class Classifier {
private:
map<DSString, map<char, float>> *words;
public:
Classifier();
Classifier(const DSString& objToCopy); // Copy Constructor
~Classifier(); // Destructor
Classifier &operator=(const Classifier& objToCopy); // Copy Assignment Overload
}
下面是 CLassifier .cpp 文件,其中不包含用于训练和预测的方法的代码。
using namespace std;
Classifier::Classifier() {
map<DSString, map<char, float>> *words;
}
// 1/3 Copy Constructor
Classifier::Classifier(const Classifier& objToCopy) {
words = new map<DSString, map<char, float>>(*objToCopy.words);
}
// 2/3 Destructor
Classifier::~Classifier() {
delete words;
words = nullptr;
}
// 3/3 Copy Assignment Operator Overload
Classifier& Classifier::operator=(const Classifier& objToCopy) {
if (this != &objToCopy) {
delete words;
words = new map<DSString, map<char, float>>(*objToCopy.words);
}
return *this;
}
当我尝试编译程序时,我收到一个关于我的复制构造函数的错误,内容如下:
Classifier.cpp:15:51: error: definition of implicitly-declared ‘constexpr Classifier::Classifier(const Classifier&)’
15 | Classifier::Classifier(const Classifier& objToCopy) {
我做错了什么,我无法编译我的程序?如果我错误地使用地图,我可以更改哪些内容以使程序仍然正常运行?有没有更好/更有效的方法来做到这一点?我需要扫描大约 20k 条推文的 CSV。
答:
头文件中有错误。您在复制构造函数中使用了错误的类名。你有这个:
Classifier(const DSString& objToCopy); // Copy Constructor
应该是这样的:
Classifier(const Classifier& objToCopy); // Copy Constructor
评论
这是在没有指针的情况下重写的代码(并修复了错误)
class Classifier {
private:
map<DSString, map<char, float>> words;
public:
};
这称为零规则,因为您不需要编写析构函数、复制构造函数或复制赋值运算符。编译器生成的是正确的。
复制构造函数声明不正确。它接受一个对象作为输入,但它需要接受一个对象。DSString
Classifier
此外,默认构造函数根本不初始化成员,这会导致代码的其余部分在尝试对成员执行操作时具有未定义的行为。words
此外,您的复制赋值运算符不需要分配一个全新的,它应该只是将数据从源复制到现有的。自己的复制分配运算符将释放旧数据并为您复制源数据。std::map
std::map
std::map
std::map
正确的 Rule-of-3 实现看起来更像是这样:
#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;
}
在 C++11 及更高版本中,您还应该通过添加移动构造函数和移动赋值运算符来实现 5 规则,例如:
#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;
}
或者:
#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);
}
话虽如此,由于已经为自己的数据实现了 Rule-of-3/5,因此您根本不需要动态使用它。您应该努力实现 Rule-of-0,只需完全删除指针并让编译器生成的构造函数/运算符为您调用对象的相应方法,例如:std::map
std::map
#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...
};
看看这有多简单?:-)
评论
Classifier