Почему программа из учебного примера не завершается аварийно?
От: Lanjeron32  
Дата: 09.12.18 18:39
Оценка:
Всем привет. Я новичок в C++ (прошу сильно не пинать за нубские вопросы).

Изучаю C++ по книге. Дошел до примера класса с копирующим конструктором:

#include <iostream>
#include <string.h>
using namespace std;
class MyString
{
   private:
      char* buffer;
   public:
      MyString(const char* initString) //конструктор
      {
          buffer = nullptr;
          cout << "Вызов конcтруктора по умолчанию" << endl;
          if (initString != nullptr)
          {
               buffer = new char[strlen(initString) + 1];
               strcpy(buffer, initString);

               cout << "buffer указывает на: " << hex;
               cout << (unsigned int*)buffer << endl;
          }
      }

      MyString(const MyString& copySource) //Копирующий конструктор
      {
          buffer = nullptr;
          cout << "Вызов копирующего конструктора" << endl;
          if (copySource.buffer != nullptr)
          {
              // Выделение собственного буфера
              buffer = new char[strlen(copySource.buffer) + 1];

              // Глубокое копирование исходного буфера в целевой
              strcpy(buffer, copySource.buffer);

              cout << "buffer указывает на: " << hex;
              cout  <<  (unsigned int*)buffer << endl;
          }
      }

      // Деструктор
      ~MyString()
      {
          cout << "Вызов деструктора" << endl;
          delete[] buffer;
      }

      int GetLength()
      {  return strlen(buffer); }

      const char* GetString()
      { return buffer; }
 };

void UseMyString(MyString str)
{
    cout << "Длина buffer в MyString равна " << dec;
    cout << str.GetLength() << " символам" << endl;

    cout << "buffer содержит: " << str.GetString() << endl;
    return;
}

int main()
{
    MyString sayHello("Hello from String Class");
    UseMyString(sayHello);

    int quit = 0;
    cin >> quit;
    return 0;
}

Этот пример при чтении книги полностью понятен. Показано, что если не будет копирующего конструктора, то функция UseMyString() будет выполнять поверхностное копирование экземпляра класса MyString. В результате будут созданы два указателя buffer на одну и ту же область памяти, а затем при выходе из main() произойдет аварийное завершение, потому что ~MyString() с delete[] в нем будет вызван дважды — при выходе из UseMyString() и при выходе из main(). В книге даже приведен скриншот аварийного завершения для среды Visual Studio.

Однако я этот пример изучал в среде Qt, и если закомментировать весь копирующий конструктор, то программа не падает. При компиляции была только парочка небольших предупреждений, а так все работает нормально. Деструктор вызывается дважды, как и должно быть, но падения не происходит.
Что это может быть? Может, Qt в отличие от Visual Studio создает какой-то копирующий конструктор по умолчанию? Если да, то можно ли его как-то увидеть?
Re: Почему программа из учебного примера не завершается аварийно?
От: Alexander G Украина  
Дата: 09.12.18 18:45
Оценка: 2 (2) +2
Здравствуйте, Lanjeron32, Вы писали:


L>Что это может быть? Может, Qt в отличие от Visual Studio создает какой-то копирующий конструктор по умолчанию? Если да, то можно ли его как-то увидеть?


Нет, копирующий конструктор по умолчанию будет поверхностно копировать.
Двойное освобождение — это неопределённое поведение.
Но при этом программа не обязательно упадёт.

Чтобы диагностировать такую ошибку, можно собрать отладочную (Debug) конфигурацию и/или использовать средства, проверяющие аллокации, такие например, как проверка Heaps из AppVerifier.
Русский военный корабль идёт ко дну!
Re: Почему программа из учебного примера не завершается аварийно?
От: niXman Ниоткуда https://github.com/niXman
Дата: 09.12.18 18:47
Оценка: +3 -1 :)
потому что С++
пачка бумаги А4 стОит 2000 р, в ней 500 листов. получается, лист обычной бумаги стОит дороже имперского рубля =)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.