使用 malloc 而不是 new 会导致 free():指针错误无效

Using malloc instead of new causes free(): invalid pointer error

本文关键字:free 指针 无效 错误 malloc new 使用      更新时间:2023-10-16

出于某种原因,使用 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

奇怪的是,注释掉mainCopy_Read调用可以解决问题,就像将malloc调用替换为对new的调用一样。使用 gdb 运行该程序表明尝试将rec分配给record_list.array[0]时发生错误。为什么会这样?我试图在这里举一个最小的例子;以前,此代码的扩展版本会导致分段错误,而不是free(): invalid pointer错误。我知道这是可怕的代码,永远不应该在严肃的程序中使用(我应该使用标准的库vectornew),但似乎有一些我不明白的东西,也没有很好的文档记录(在初学者可以访问的资源中,无论如何)关于mallocnew之间的区别,这是此代码问题的根源。

我不明白malloc和new之间的区别

你需要阅读更多关于C++的信息,例如一些C++编程书籍,以及一个好的C++参考网站。是的,C++是一种非常困难的语言(你需要多年的工作才能掌握它)。稍后,您可以深入了解 C++11 标准 n3337(或一些更新的 C++ 标准)。你当然需要准确地理解构造函数和析构函数的角色(并解释这需要很多页,远远超过你在任何StackOverflow答案中可以合理期望的)。

你需要执行构造函数的代码(这是用new完成的,但不能用malloc完成的) - 稍后在释放内存之前也应该执行析构函数。析构函数由delete调用(在许多其他情况下),但当然不是由free调用。另请阅读有关五法则和 RAII 的信息。

如果可能,您应该更喜欢使用智能指针。有时(例如,对于循环引用)它们是不够的。

害怕未定义的行为。

valgrind 工具对于搜寻与内存相关的错误很有用。您还应该使用所有警告和调试信息进行编译,因此请使用 GCCg++ -Wall -Wextra -g。您可能还希望使用静态源代码分析器工具,例如 clang-analyzer 或 Frama-C。使用它们可能需要大量专业知识;没有灵丹妙药

你的struct Record_array是错误的:更喜欢使用std::vector<Record>。阅读有关标准C++容器的更多信息。

Record的构造函数将调用str1str2的构造函数(它,std::string-s 的构造函数应用于两个不同的位置)。如果不将其Record调用构造函数,则str1str2保持某种未定义的状态(因此一旦使用它们,您就会有一些未定义的行为)。

malloc&free(对于 C)与newdelete(对于 C++)之间的主要区别在于构造函数和析构函数的参与方式。当然,malloc&free忽略了它们,但new&delete却没有。内存分配失败(例如,当虚拟内存耗尽时)的处理方式也不同。

附言。实际上,您永远不应该在C++代码中使用malloc,除非 - 仅在极少数情况下 - 在定义自己的operator new时。因为malloc不调用构造函数C++(但new调用)。另外,请理解 C和 C++ 是不同的编程语言malloc用于 C,而不是 C++。许多C++标准库实现在标准::operator new的实现中使用malloc,并在::operator delete中使用free