我有一个函数,它返回一个指向双精度数组的指针:
double * centerOfMass(System &system) {
long unsigned int size = system.atoms.size();
double x_mass_sum=0.0; double y_mass_sum=0.0; double z_mass_sum=0.0; double mass_sum=0.0;
for (int i=0; i<=size; i++) {
double atom_mass = system.atoms[i].m;
mass_sum += atom_mass;
x_mass_sum += system.atoms[i].pos["x"]*atom_mass;
y_mass_sum += system.atoms[i].pos["y"]*atom_mass;
z_mass_sum += system.atoms[i].pos["z"]*atom_mass;
}
double comx = x_mass_sum/mass_sum;
double comy = y_mass_sum/mass_sum;
double comz = z_mass_sum/mass_sum;
double* output = new double[3]; // <-------- here is output
output[0] = comx*1e10; // convert all to A for writing xyz
output[1] = comy*1e10;
output[2] = comz*1e10;
return output;
}
当我尝试通过将数组保存到变量(在不同的函数中)来访问输出时,程序运行时会出现分段错误(但编译正常):
void writeXYZ(System &system, string filename, int step) {
ofstream myfile;
myfile.open (filename, ios_base::app);
long unsigned int size = system.atoms.size();
myfile << to_string(size) + "\nStep count: " + to_string(step) + "\n";
for (int i = 0; i < size; i++) {
myfile << system.atoms[i].name;
myfile << " ";
myfile << system.atoms[i].pos["x"]*1e10;
myfile << " ";
myfile << system.atoms[i].pos["y"]*1e10;
myfile << " ";
myfile << system.atoms[i].pos["z"]*1e10;
myfile << "\n";
}
// get center of mass
double* comfinal = new double[3]; // goes fine
comfinal = centerOfMass(system); // does NOT go fine..
myfile << "COM " << to_string(comfinal[0]) << " " << to_string(comfinal[1]) << " " << to_string(comfinal[2]) << "\n";
myfile.close();
}
运行程序会产生正常函数,直到它尝试调用centerOfMass
。
我检查了大多数可能的解决方案;我想我只是缺乏对C ++中指针及其范围的理解。我在PHP中经验丰富,因此明确处理内存是有问题的。
谢天谢地
答案 0 :(得分:4)
我不确定system.atoms
的类型。如果它是std::vector
之类的STL容器,则函数for
内的centerOfMass
循环的条件部分是错误的。
long unsigned int size = system.atoms.size();
for (int i=0; i<=size; i++) {
应该是
long unsigned int size = system.atoms.size();
for (int i=0; i<size; i++) {
PS1:您可以使用Range-based for loop (since C++11)来避免此类问题。
PS2:你没有delete[]
动态分配的数组;考虑使用std::vector,std::array或std::unique_ptr代替它们,它们旨在帮助您避免此类问题。
答案 1 :(得分:1)
除了songyuanyao指出的问题之外,writeXYZ()
中函数的使用会导致内存泄漏。
要查看此内容,请注意centerOfMass()
执行此操作(删除了无关的详细信息)
double* output = new double[3]; // <-------- here is output
// assign values to output
return output;
和writeXYZ()
确实如此(请注意,我更改了评论以反映实际发生的情况,与您对您认为发生的事情的评论截然不同)
double* comfinal = new double[3]; // allocate three doubles
comfinal = centerOfMass(system); // lose reference to them
// output to myfile
如果多次调用writeXYZ()
,则每次都会泄漏三个double
,即使在某处,delete [] comfinal
随后也会被执行。如果多次调用此函数(例如,在循环中),最终泄漏的内存量可能超过可用内存量,后续分配将失败。
此问题的一个解决方法是将writeXYZ()
的相关部分更改为
double* comfinal = centerOfMass(system);
// output to myfile
delete [] comfinal; // eventually
在上面介绍std::unique_ptr
将缓解症状,但这比代码中的良好逻辑更令人高兴(仅分配内存以立即丢弃它而不使用它很少是好技术)。
实际上,最好使用标准容器(std::vector
等)并避免使用运算符new
。但他们仍然要求你保持在一定范围内。