出于某种原因,使用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
之间的区别,这是该代码问题的根源。
我不明白malloc和new之间的区别
你需要阅读更多关于C ++的内容,例如:一些C++ programming书,和一个很好的C++ reference网站。是的,C ++是一门非常困难的语言(你需要多年的工作来掌握它)。稍后,您可以深入研究C ++ 11标准n3337(或更新的C ++标准)。你当然需要准确理解constructors和destructors的作用(并解释这需要很多页面,远远超过你在任何StackOverflow答案中可以合理预期的内容)。
您需要执行constructors的代码(使用new
但不能使用malloc
) - 稍后在释放内存之前还应执行析构函数。析构函数由delete
(以及许多其他情况)调用,但当然不是由free
调用。阅读有关rule of five和RAII的信息。
你应该尽可能使用smart pointers。有时(例如,对于循环引用),它们是不够的。
valgrind工具可用于捕获与内存相关的错误。您还应编译所有警告和调试信息,所以g++ -Wall -Wextra -g
与GCC。您可能还想使用静态源代码分析工具,如clang-analyzer或Frama-C。使用它们可能需要大量的专业知识;有no silver bullet。
你的struct Record_array
错了:更喜欢使用std::vector<Record>
。阅读有关标准C ++ containers的更多信息。
你的Record
的构造函数将调用str1
和str2
的构造函数(它,std::string
-s的构造函数应用于两个不同的位置)。如果你不调用那个Record
构造函数,str1
和str2
会保持一些未定义的状态(所以你使用它们就会有一些undefined behavior)。
malloc
和free
(对于C)和new
和delete
(对于C ++)的主要区别在于构造函数和析构函数的参与方式。当然,malloc
和free
忽略了它们,但不是new
和delete
。存储器分配的失败(例如,当虚拟存储器耗尽时)也以不同方式处理。
PS。在实践中,你不应该在C ++代码中使用malloc
,除非 - 仅在极少数情况下 - 定义自己的operator new
时。因为malloc
不会调用C ++构造函数(但new
会这样做)。另外,请理解C和C ++是不同的编程语言,malloc
是C语言,而不是C ++。许多C++ standard library实现在他们的标准malloc
的实现中使用::operator new
并在他们的free
中使用::operator delete
。