Класс Деструктор SEGFAULT

В моем проекте у меня есть два класса, 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_map а также list получить, но при вызове стандартного класса деструктора 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 );

}

2

Решение

Ваше Правило Три не является полным. Поскольку у вас есть член-указатель, вы хотите убедиться, что реализовали конструктор копирования, оператор копирования а также деструктор.

Теперь, потому что у вас есть указатель на vector член, я собираюсь сказать вам, что вы не должно быть этого, но вместо этого просто есть std::vector<std::string> или std::unique_ptr<std::vector<std::string> >,

Я не знаю Зачем вы решили, что нужно держать указатель на контейнер, но это, как правило, не веская причина и подвержено ошибкам.

Вы могли бы держать ссылка в контейнер, но вы должны убедиться, что он инициализирован в ctor.

Проблема с указателями заключается в том, что их слишком легко найти в качестве «решения», но на самом деле они чрезвычайно подвержены ошибкам и их трудно использовать. если ты перестал думать об указателях и перестав быть склонным использовать их на каждом шагу, вам будет намного легче.

4

Другие решения

Я не вижу никакой инициализации переменной productionContent. Попробуйте инициализировать его в NULL с инициализаторами. Значения по умолчанию для неинициализированных переменных-членов не равны NULL.

Это означает, что productionContent! = NULL всегда будет истинным из-за того, что он начинает отличаться от NULL.

Попробуйте что-то подобное во всех ваших конструкторах:

Production::Production( const Production& copy_me ) : productionContent(NULL)
{
...
1

Есть два варианта.

  1. Либо вы динамически выделяете вектор в Production, в этом случае вам нужен оператор присваивания, чтобы сделать глубокую копию векторного указателя. Ваш конструктор копирования должен сделать то же самое. В этом случае вы должны следовать правило трех.

  2. Или вы берете указатель на вектор в Production конструктор и не выполнять глубокую копию, в этом случае Production не владеет вектором и не должен удалять его в деструкторе.

Если у вас есть случай 1, я предлагаю сбросить указатель и удерживать std::vector по значению.

1

Если у вас есть хорошая или плохая причина для указателя, используйте std :: shared_ptr (в качестве параметра члена и конструктора), чем меньше вы делаете, тем больше вы находитесь. std :: shared_ptr создаст для вас nullptr и удаление!

0
По вопросам рекламы [email protected]