Использование malloc вместо новых вызывает free (): ошибка неверного указателя - PullRequest
0 голосов
/ 10 марта 2019

По какой-то причине компиляция следующего кода с помощью gcc и запуск двоичного файла, который он создает в Ubuntu, выдает ошибку free(): invalid pointer:

#include <stdlib.h>
#include <fstream>
#include <string>
#include <iostream>
#include <sstream>
#include <ios>
#include <new>

struct arr_double_size {
   double *array;
   int size;
};

struct Record {
   int ID;
   std::string str1;
   std::string str2;
   int num;
   struct arr_double_size values;
};

struct Record_array {
   struct Record *array;
   int size;
};

void Copy_Read(void) {
   std::ifstream file{"in_file"};
   std::ofstream new_file{"out_file"};
   std::string line;
   while (std::getline(file,line)) {
      new_file << line << std::endl;
   }
   file.close();
   new_file.close();
}

int main(void) {
   Copy_Read();
   struct Record rec;
   struct arr_double_size values;
   values.size = 1;
   values.array = (double *)malloc(1 * sizeof(double));
   values.array[0] = 72.12;
   rec.ID = 2718;
   rec.str1 = "Test1";
   rec.str2 = "Test2";
   rec.num = 1;
   rec.values = values;
   struct Record_array record_list;
   record_list.size = 1;
   record_list.array = (struct Record *)malloc(1 * sizeof(struct Record));
   record_list.array[0] = rec;   
   return 0;
}

Содержимое in_file:

TEST TEST TEST

Странно, но закомментирование вызова в main на Copy_Read решает проблему, также как и замена вызовов на malloc вызовами на new. Запуск программы с помощью gdb показывает, что ошибка возникает при попытке назначить rec для record_list.array[0]. Почему это происходит? Я попытался привести минимальный пример здесь; предыдущие, расширенные версии этого кода приводили к ошибкам сегментации вместо ошибки free(): invalid pointer. Я знаю, что это ужасный код, который никогда не должен использоваться в серьезной программе (я должен использовать стандартную библиотеку vector и new), но, кажется, есть кое-что, чего я не понимаю, и который недостаточно документирован (в любом случае, в ресурсах, доступных для начинающих) о разнице между malloc и new, которая является источником проблем с этим кодом.

1 Ответ

0 голосов
/ 10 марта 2019

Я не понимаю о разнице между malloc и new

Вам нужно прочитать намного больше о C ++ , например, немного C ++ программирование книга и хороший C ++ справочник сайт. Да, C ++ - очень сложный язык (вам понадобятся годы работы, чтобы освоить его). Позже вы можете погрузиться в стандарт C ++ 11 n3337 (или более поздний стандарт C ++). Вам, безусловно, нужно понимать точно роль конструкторов и деструкторов (и объяснять, что это занимает много страниц, гораздо больше, чем можно разумно ожидать в любом ответе StackOverflow ).

Вам нужно иметь код ваших конструкторов для выполнения (и это делается с new, но не с malloc) - и позже деструкторы также должны быть выполнены, прежде чем освободить память. Деструкторы называются delete (и во многих других случаях), но, конечно, не free. Читайте также о правиле пяти и о RAII .

Если возможно, вы должны использовать интеллектуальные указатели . Иногда (например, для циклических ссылок) их недостаточно.

Бояться неопределенного поведения .

Инструмент valgrind полезен для поиска ошибок, связанных с памятью. Вы также должны скомпилировать все предупреждения и отладочную информацию, поэтому g++ -Wall -Wextra -g с GCC . Вы также можете использовать статические анализаторы исходного кода, такие как clang-analyzer или Frama-C . Использование их может потребовать большого опыта; есть нет серебряной пули .

Ваш struct Record_array неправильный: предпочитайте использовать std::vector<Record>. Узнайте больше о стандартных контейнерах C ++ .

Конструктор вашего Record будет вызывать конструктор str1 и str2 (чтобы он, конструктор std::string, применялся в двух разных местах). Если вы не называете это конструктором Record, str1 и str2 остаются в каком-то неопределенном состоянии (поэтому у вас есть некоторое неопределенное поведение , как только вы их используете).

Основное различие между malloc & free (для C) и new и delete (для C ++) заключается в способе участия конструкторов и деструкторов. Конечно, malloc & free игнорируют их, но не new & delete. Сбой выделения памяти (например, когда виртуальная память исчерпана) также обрабатывается по-разному.

PS. На практике вы никогда не должны использовать malloc в коде C ++ , за исключением - только в редких случаях - при определении собственного operator new. Потому что malloc не вызывает конструкторы C ++ (а new делает). Также, пожалуйста, поймите, что C и C ++ разные языки программирования , а malloc для C, а не C ++. Многие реализации C ++ стандартной библиотеки являются , использующими malloc в их реализации стандарта ::operator new и использующими free в их ::operator delete.

...