在我的项目中,我有两个类,EarleyParser
类:
class EarleyParser
{
public:
EarleyParser();
virtual ~EarleyParser();
void initialize( string filePath, bool probabilityParse );
private:
bool probabilityParser;
typedef unordered_map< string, list<Production> > productionHashTable;
productionHashTable earlyHashTable;
};
和Production
类:
class Production
{
public:
Production();
Production( float productionProbability, int productionLength, vector< string >* productionContent );
Production( const Production& copy_me );
virtual ~Production();
float getProductionProbability();
int getProductionLength();
vector< string >* getProductionContent();
private:
float productionProbability;
int productionLength;
vector< string >* productionContent;
void setProductionProbability( float productionProbability );
void setProductionLength( int productionLength );
void setProductionContent( vector< string >* productionContent );
};
正如您在上面所看到的,EarlyParser
类的成员元素是unordered_map
,其关键元素是一个字符串,值为list
来自{{1}的元素}。class。
代码正常运行,Production
和unordered_map
已填充,但在调用list
的标准析构函数类时,我遇到了分段错误。
据我所知,EarleyParser
的默认析构函数应该调用EarleyParser
的默认析构函数,该析构函数应该调用unordered_map
的一个,它应该调用每个元素的默认析构函数list
类的内容,如下所示:
Production
使用Valgrind和GDB进行反向跟踪并没有给我如何解决分段错误的帮助,这完全在析构函数44行的Production::~Production()
{
if( this->productionContent != NULL )
delete this->productionContent; <- line 44
}
中给出。
我应该实现析构函数类,还是默认的析构函数可以正常? 关于什么可能导致分段错误的任何想法?
添加复制构造
EarleyParser.cpp
答案 0 :(得分:4)
你的三条规则是不完整的。由于您有指针成员,因此您需要确保已实现复制构造函数,复制赋值运算符和析构函数。
现在,因为你有一个指向vector
成员的指针,我会告诉你,不应该有,而是只有一个std::vector<std::string>
或std::unique_ptr<std::vector<std::string> >
。
我不知道为什么你决定需要一个指向容器的指针,但这主要不是一个好理由,而且容易出错。
您可以将引用保存到容器中,但您需要确保它已在ctor中初始化。
指针的问题在于它们太容易作为“解决方案”被抓取,但实际上非常容易出错且难以使用。如果你停止考虑指针并且不再倾向于在每个转弯处使用它们,那么你就会有更轻松的时间。
答案 1 :(得分:1)
有两种选择。
要么在Production
中动态分配向量,在这种情况下,需要赋值运算符来执行向量指针的深层复制。您的复制构造函数应该这样做。在这种情况下,您应该关注rule of three。
或者,您在Production
构造函数中指向一个向量,并且不执行深层复制,在这种情况下Production
不拥有该向量,不应删除它析构函数。
如果您有案例1,我建议删除指针并按值保持std::vector
。
答案 2 :(得分:1)
我没有看到productionContent变量的任何初始化。尝试使用初始值设定项将其初始化为NULL。未初始化的成员变量的默认值不为空。
这意味着productionContent!= NULL将永远为真,因为它开始是非NULL的事实。
在所有构造函数中尝试这样的事情:
Production::Production( const Production& copy_me ) : productionContent(NULL)
{
...
答案 3 :(得分:0)
对于指针有任何好或坏的理由,使用std :: shared_ptr(作为成员和构造函数参数),你做的越少,你就越多。 std :: shared_ptr会为你做出nullptr和删除!