Обратите внимание, что здесь вы не перезаписываете переменную x
, а назначаете ее. Это вызовет значение по умолчанию operator=
для вашего типа, что примерно приведет к выполнению следующего кода
- Выполнен конструктор
TermProd::TermProd(TermPtr, TermPtr)
- Значения
m_lhs
и m_rhs
копируются в значение x
- Деструктор для значения, созданного на шаге # 1, теперь запущен, а
m_lhs
и m_rhs
удалены
На данный момент у вас есть реальная проблема. После шага № 2 значение x
и временное значение, созданные на шаге № 1, имеют одинаковые значения m_lhs
и m_rhs
. Деструктор на шаге 3 удаляет их, но x
все еще имеет ссылку на них, которая теперь эффективно указывает на мертвую память
Чтобы решить эту проблему, вам нужно добавить собственную operator=
, которая правильно обрабатывает семантику назначения. Например
TermProd& operator=(const TermProd& other) {
if (&other != this) {
delete m_lhs;
delete m_rhs;
m_lhs = other.m_lhs->clone();
m_rhs = other.m_rhs->clone();
}
return *this;
};
Чтобы быть корректным для всех сценариев, вам также нужно добавить правильный конструктор копирования
TermProd::TermProd(const TermProd& other) :
m_lhs(other.m_lhs->clone()),
m_rhs(other.m_rhs->clone())
{
}
Действительно, чтобы сделать это чрезвычайно просто, вы должны рассмотреть возможность использования std::shared_ptr<Term>
в качестве значения для TermPtr
. Это указатель, который сделает совместное использование без всех вышеупомянутых издержек