在我的项目中,我有两个类,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
,其关键元素是一个字符串,值是Production
类中元素的list
。
代码工作正常,unordered_map
和list
被填充,但是在调用EarleyParser
的标准析构函数类时,我得到了分段错误。
据我了解,EarleyParser
的默认析构函数应该调用unordered_map
的默认析构函数,该析构函数应该调用list
之一,该应为其每个元素调用Production
类的默认析构函数,如下所示:
Production::~Production()
{
if( this->productionContent != NULL )
delete this->productionContent; <- line 44
}
使用 Valgrind 和 GDB 进行回溯跟踪并没有给我太多关于如何解决分段错误的帮助,这在析构函数第 44 行的EarleyParser.cpp
中给出
。我应该实现析构函数类,还是默认析构函数没问题? 关于可能导致分段错误的原因的任何想法?
添加了复制构造函数
Production::Production( const Production& copy_me )
{
if( this->productionContent != NULL )
this->productionContent = NULL;
this->setProductionProbability( copy_me.productionProbability );
this->setProductionLength( copy_me.productionLength );
this->setProductionContent( copy_me.productionContent );
}
你的三法则不完整。由于您有一个指针成员,因此您希望确保已实现复制构造函数、复制赋值运算符和析构函数。
现在,因为你有一个指向vector
成员的指针,所以我要告诉你,你不应该有它,而只是有一个std::vector<std::string>
或一个std::unique_ptr<std::vector<std::string> >
。
我不知道你为什么决定需要持有指向容器的指针,但这主要不是一个很好的理由,而且容易出错。
您可以保存对容器的引用,但需要确保它在 ctor 中初始化。
指针的问题在于它们太容易被当作"解决方案",但实际上非常容易出错且难以使用。如果你不再考虑指针,不再倾向于动不动就使用它们,那么你就会更容易。
我没有看到生产内容变量的任何初始化。 尝试使用初始值设定项将其初始化为 NULL。 未初始化成员变量的默认值不为 null。
这意味着 productionContent != NULL 将始终为真,因为它一开始不是 NULL。
在所有构造函数中尝试类似的东西:
Production::Production( const Production& copy_me ) : productionContent(NULL)
{
...
有两个选项。
-
要么在
Production
中动态分配向量,在这种情况下,您需要赋值运算符来执行向量指针的深层复制。复制构造函数也应该这样做。在这种情况下,您应该遵循三法则。 -
或者,在
Production
构造函数中获取指向矢量的指针,并且不执行深层复制,在这种情况下,Production
不拥有该矢量,不应在析构函数中删除它。
如果您有情况 1,我建议删除指针并按值按住std::vector
。
对于指针的任何好或坏的理由,请使用 std::shared_ptr(作为成员和构造函数参数),您做的越少,您就越多。 std::shared_ptr 将为您制作 nullptr 和删除!