@krot0glot

Почему запускается деструктор в данном примере?

Основной код:
spoiler
#include <iostream>

using std::cout;

class MyString
{
public:
	MyString();
	MyString(const char *);
	~MyString();

	void Print() 
	{ cout << m_string << '\t' << m_length << '\n'; }

private:
	char *m_string;
	size_t m_length;

	void Copy(const char *);
	size_t StrLen(const char *);
};

MyString::MyString()
{ 
	m_string = nullptr;
	m_length = 0ull;
}

MyString::MyString(const char *string)
{
	Copy(string);
}

MyString::~MyString()
{
	if (m_string == nullptr)
		return;

	delete[] m_string;
}

size_t MyString::StrLen(const char *string)
{
	size_t len = 0ull;
	while (string[len] != '\0')
		++len;

	return len;
}

void MyString::Copy(const char *string)
{
	m_length = StrLen(string);
	m_string = new char[m_length + 1];

	if (m_string == nullptr)
		return;

	for (size_t i = 0; i < m_length; ++i)
		m_string[i] = string[i];

	m_string[m_length] = '\0';
}

int main()
{
	MyString a("hi");
	a.Print();

	return EXIT_SUCCESS;
}

Метод, который не вызывает деструктор:
spoiler
void MyString::Copy(const char *string)
{
	m_length = StrLen(string);
	m_string = new char[m_length + 1];

	if (m_string == nullptr)
		return;

	for (size_t i = 0; i < m_length; ++i)
		m_string[i] = string[i];

	m_string[m_length] = '\0';
}

Метод, после которого вызывается деструктор:
spoiler
MyString MyString::Copy(const char *string)
{
	m_length = StrLen(string);
	m_string = new char[m_length + 1];

	if (m_string == nullptr)
		return *this;

	for (size_t i = 0; i < m_length; ++i)
		m_string[i] = string[i];

	m_string[m_length] = '\0';

        return *this;
}
  • Вопрос задан
  • 236 просмотров
Решения вопроса 2
@vanyamba-electronics
Просто у вас ошибка в этой строке
MyString MyString::Copy(const char *string) { }
Вы возвращаете копию объекта. Он нигде не используется:
MyString::MyString(const char *string)
{
  Copy(string); // Вот здесь
}

И для этой копии вызывается деструктор.

А должно быть так:
MyString& MyString::Copy(const char *string) { }
В этом случае метод вернёт ссылку на объект.

Но тогда вам следует объявить этот метод как статичный и назвать его не "копировать", а "создать":
class MyString {
   MyString(const char* string);
   static MyString* Create(const char *string);
};

MyString::MyString(const char *string)
{
  m_length = StrLen(string);
  m_string = new char[m_length + 1];

  if (m_string != nullptr) {
     for (size_t i = 0; i < m_length; ++i)
       m_string[i] = string[i];

       m_string[m_length] = '\0';
   }
}
   
MyString* MyString::Create(const char *string)
{
  return new MyString(string);
}

Обратите внимание - мой метод возвращает указатель. Это такое правило - никогда не возвращайте по ссылке объект, который создаётся внутри функции. Иначе потом будете рефакторить весь код.

В C++ нет стандартного соглашения, как должен поступить компилятор с объектом, возвращённым из функции по ссылке. Одни компиляторы такие объекты просто тихо удаляют, другие - нет.
И вот, у вас объект в памяти есть, вы его не удаляли, и он даже доступен. Всё работает.
Но потом вы создаёте какой-то новый объект, и у вас крашится программе при попытке доступа к прошлому объекту.
Что такое? Почему компилятор сгенерил код, который затирает память? Куда подевался объект в том месте программы, в котором раньше всё работало?
Просто физически нереально отыскать место возникновения ошибки через неделю, за которую вы написали ещё 30 тысяч строк кода.
Поэтому всегда возвращайте объект из функции только по указателю.
Ответ написан
Комментировать
@rPman
Сам copy никак не вызывает деструктор
деструктор будет вызван автоматически по завершению области действия места где объект был создан, т.е. после завершения main

Если же ты добавляешь *this в return Copy то у тебя возникает вызов деструктора этого возвращенного объекта, который не используется, а затем еще раз по завершению программы, собственно программа у тебя будет мусор на экран выводить вместо ожидаемого hi.

Добавь в деструктор вывод на экран "destructor", увидишь

Причина (если честно для меня не очевидная) в том что ты мешаешь два подхода - работа с объектами и работа со ссылкой на объект, преобразованный в сам объект (return *this), рекомендуется не мешать эти два подхода
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы