2

在我的项目中,我有两个类,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中元素的一个Production

代码可以正常工作,并且unordered_maplist被填充,但是在调用标准析构函数类时EarleyParser出现分段错误。

据我了解,默认析构函数EarleyParser应该调用的默认析构函数unordered_map应该调用其中一个list应该调用其每个元素的Production类的默认析构函数,如下所示:

Production::~Production()
{
    if( this->productionContent != NULL )
        delete this->productionContent; <- line 44
}

使用 Valgrind 和 GDB 进行回溯并没有给我太多帮助来解决分段错误,这在EarleyParser.cpp析构函数的第 44 行中给出。

我应该实现析构函数类,还是默认析构函数可以?关于可能导致分段错误的任何想法?

添加的副本构造函数

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 );

}
4

4 回答 4

4

你的三法则不完整。由于您有一个指针成员,因此您要确保已实现复制构造函数复制赋值运算符析构函数

现在,因为你有一个指向vectormember 的指针,所以我要告诉你,你不应该有 that,而应该只有 astd::vector<std::string>或 a std::unique_ptr<std::vector<std::string> >

我不知道您为什么决定需要保存指向容器的指针,但这通常不是一个好的理由,而且容易出错。

您可以持有对容器的引用,但您需要确保它已在 ctor 中初始化。

指针的问题在于它们太容易被抓住作为“解决方案”,但实际上极易出错且难以使用。如果您不再考虑指针并且不再倾向于在每一个转折点使用它们,那么您的时间就会轻松得多。

于 2012-10-02T12:33:55.713 回答
1

有两种选择。

  1. 要么在 中动态分配一个向量Production,在这种情况下,你需要一个赋值运算符来对向量指针进行深拷贝。您的复制构造函数也应该这样做。在这种情况下,您应该遵循三规则

  2. 或者,您在构造函数中获取指向向量的指针Production并且不执行深度复制,在这种情况下Production不拥有该向量并且不应在析构函数中将其删除。

如果您有案例 1,我建议删除指针并按std::vector值保存。

于 2012-10-02T12:30:33.500 回答
1

我没有看到 productionContent 变量的任何初始化。尝试使用初始化程序将其初始化为 NULL。未初始化的成员变量的默认值不为空。

这意味着 productionContent != NULL 将始终为真,因为它开始时不是 NULL。

在所有构造函数中尝试这样的事情:

Production::Production( const Production& copy_me ) : productionContent(NULL)
{
...
于 2012-10-02T12:34:05.123 回答
0

您对指针有任何好的或坏的理由,请使用 std::shared_ptr (作为成员和构造函数参数),您做的越少,您做的越多。std::shared_ptr 将为您生成 nullptr 和删除!

于 2012-10-02T13:04:46.070 回答