使用malloc而不是新原因会导致free():无效的指针错误

时间:2019-03-10 07:16:57

标签: c++ segmentation-fault malloc new-operator

由于某种原因,使用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错误。我知道这是可怕的代码,永远不要在严肃的程序中使用(我应该使用标准库vectornew),但是似乎有些我不理解的东西,这是关于mallocnew之间的差异(这是此代码存在问题的根源)的文献资料不足(无论如何,对于初学者来说都是这样)。

1 个答案:

答案 0 :(得分:0)

  

我不了解malloc和new之间的区别

您需要阅读有关C ++的更多信息 ,例如一些C++ programming书和一个不错的C++ reference网站。是的,C ++是一门非常困难的语言(您需要花费大量的时间才能掌握它)。稍后,您可以深入研究C ++ 11标准n3337(或更新的C ++标准)。当然,您确实需要准确地了解constructorsdestructors的作用(并说明这需要很多页面,远远超出了您在StackOverflow答案中可以合理预期的范围)。 / p>

您需要先执行constructors的代码(这是通过new完成的,而不能通过malloc完成的)–之后,析构函数也应先执行释放内存。 delete(在许多其他情况下)调用析构函数,但是free当然不会。另请参阅有关rule of fiveRAII的信息。

您应该尽可能使用smart pointers。有时(例如用于循环引用)还不够。

undefined behavior

valgrind工具可用于寻找与内存相关的错误。您还应该编译所有警告和调试信息,因此将g++ -Wall -Wextra -gGCC一起使用。您可能还希望使用静态源代码分析器工具,例如clang-analyzerFrama-C。使用它们可能需要很多专业知识;有no silver bullet

您的struct Record_array是错误的:更喜欢使用std::vector<Record>。详细了解标准C ++ containers

您的Record的构造函数将调用str1str2的构造函数(即std::string的构造函数应用于两个不同的位置)。如果您不调用该Record构造函数,则str1str2保持某种未定义状态(因此,使用它们后您将立即拥有一些undefined behavior)。

mallocfree(对于C)与newdelete(对于C ++)之间的主要区别是构造函数和析构函数的涉及方式。当然,mallocfree会忽略它们,但不会忽略newdelete。内存分配失败(例如,虚拟内存耗尽时)的处理方式也不同。

PS。实际上,除了在极少数情况下,在定义自己的malloc时,切勿在C ++代码中使用operator new 。因为malloc不会调用C ++构造函数(而new会调用)。另外,请理解 C和C ++是不同编程语言,而malloc是C而不是C ++。许多C++ standard library实现在标准malloc的实现中使用 {em> ::operator new,在其free的使用::operator delete中。