我有一个问题是,malloc / realloc内存将包含一个class / struct数组(我试过结构和类,问题仍然存在)包含std向量的成员。我知道我可以通过使用new和std数组容器类来解决这个问题。但是,我想更好地理解为什么当我使用realloc而不是malloc时,以下小代码崩溃(因为我在将较大的代码项目从C转换为C ++的上下文中遇到了这个问题)。似乎我不一定在类/结构中设置向量的初始大小(有些编译器允许有些不...) - 所以什么是类中的向量 - 一个舒适的指针?
谢谢, 启
#include <stdlib.h>
#include <limits.h>
#include <float.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <sys/types.h>
#include <vector>
/* mpic++ -O3 -ffast-math -pedantic vec-alloc.cpp -o vec-alloc */
using namespace std;
class float_vector{
public:
double x;
double y;
double z;
float_vector() : x(0), y(0), z(0) {};
};
class voxel{
public:
float_vector x;
vector<double> y;
voxel() : x() {};
};
int main(){
int i;
double d =1.111;
voxel v0, *Comp, *Comp2;
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
for(i=0;i<10;++i) Comp[i] = v0;
printf("malloc done\n");
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
printf("realloc done\n");
for(i=0;i<10;++i) Comp[i].y.push_back(d);
for(i=0;i<10;++i) printf("%lf\n",Comp[i].y[0]);
for(i=0;i<10;++i) Comp2[i].y.push_back(d); // this crashes
for(i=0;i<10;++i) printf("%lf\n",Comp2[i].y[0]);
return 1;
}
答案 0 :(得分:2)
如果对非POD类使用malloc()
,则必须手动调用构造函数(通过放置new
)和析构函数。
使用未正确构造的对象会导致未定义的行为,这通常意味着指针崩溃。
显然,为对象释放内存而不对其进行适当的破坏会导致UB。
您的代码必须如下所示:
MyClass *arr = (MyClass *) malloc(10 * sizeof (MyClass));
for (int i = 0; i < 10; i++)
new (arr + i) MyClass; // This line calls constructors
// Do something with the array here
for (int i = 0; i < 10; i++)
arr[i].~MyClass(); // This line calls destructors.
free(arr);
此要求还意味着您不能将realloc()
与非POD类型一起使用,因为它不会为旧数组调用析构函数,也不会为新数组调用构造函数。
手动重新分配代码可能如下所示:
MyClass *new_ptr = (MyClass *) malloc(new_size * sizeof (MyClass));
for (int i = 0; i < new_size; i++)
new (new_ptr + i) MyClass((MyClass &&) old_ptr[i]);
for (int i = new_size; i < old_size; i++)
new (new_ptr + i) MyClass;
for (int i = 0; i < old_size; i++)
old_ptr[i].~MyClass();
free(old_ptr);
请记住,上面的代码并不是真正的异常安全。如果构造函数抛出异常并捕获它,那么您需要确保正确地破坏构造的对象。 谢谢@SteveJessop。
现在,当您了解为什么在C ++中通常应该避免使用malloc()
/ free()
时,我希望您能够更加安全new
/ {{ 1}},为你完成所有构造和破坏。
答案 1 :(得分:1)
这可能与realloc
无关。当您在开始时执行此操作时,您的代码已经具有未定义的行为:
for(i=0;i<10;++i) Comp[i] = v0;
Comp[0]
从未被初始化(因为malloc
返回未初始化的内存 - 它无法知道您打算使用它的类型,因此即使它想要也不可能初始化它)。然后您的代码尝试分配给它。对于vector
等复杂类型,不允许这样做。
为什么不允许?在vector的情况下,因为当您分配给已经保存数据的向量时,它需要释放旧数据。如果没有什么可以自由的,它就不会有任何自由。但是未初始化的内存可能根本没有任何值,所以vector
似乎有些东西应该被释放,实际上根本不是一个可释放的指针,更不用说vector
由于这项任务应该解放。如果没有初始化,就会违反“this指针数据成员始终是空指针,或者是某个内存的地址,这是向量的责任”的某些类不变,因此vector
代码不起作用。
假设您的代码以某种方式超越了这一点,您仍然无法realloc
包含vector
的内存。从标准的角度来看,这是因为vector<double>
不是POD类型,因此它的逐字节副本(包括由realloc
完成的)会导致未定义的行为。 / p>
从特定实现的角度来看,我们可能会问自己,实现者可能编写哪些代码,在逐字节复制向量的情况下会出错。一个假设的答案是,在某些情况下,vector
可以包含指向自己身体的指针(作为所谓的小矢量优化的一部分)[编辑:实际上,我认为在内部不可能进行小矢量优化出于其他原因的标准,但我的一般观点是,因为向量不是POD,所以实现者可以自由地使用他们的创造力]。如果向量被重定位,则该指针不再指向向量自身的主体,因此不满足类不变量,并且代码不再有效。为了让实现者能够自由地编写这样的代码,作为类用户的自由受到限制,并且不允许通过逐字节复制来重定位向量(或通常任何非POD类型)。
答案 2 :(得分:0)
var time = toDays(21);
function toDays(years)
{
var time;
time = 365*years;
return time;
}
document.write("My age is " + time);
/* dynamically allocate memory */
Comp= (voxel*)malloc(10*sizeof(voxel));
现在是指向未初始化内存的指针。
Comp
这会尝试调用for(i=0;i<10;++i) Comp[i] = v0;
,但Comp[i].operator=(v0)
不是有效的初始化对象。在一个简单的测试/调试案例中,我们可能会很幸运,但在实践中我们会得到垃圾,而矢量会尝试释放/使用无效指针。
这并不仅仅意味着你需要Comp[i]
内存,你不能假设初始化对象期望找到什么值。
calloc()
Comp2现在是指向单个体素的指针,并且没有“realloc”。
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc done\n");
这只是古怪。它始于Comp2指向单个体素。然后,由于某种原因,您获取第一个元素(for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
)的地址而不是仅使用第一个元素(&Comp2[0]
)的地址,并将其重新分配到相同的大小。然后,将v0复制到最后一个位置的未初始化内存中:
Comp2
简短:您无法将Comp2 = [...uninit...]
for (i = 0
realloc(i + 1 == 1)
Comp2 = [...uninit...]
^-- v0
i++
realloc(i+1 == 2)
Comp2 = [.....v0.....][...uninit...]
^--v0
或malloc
或calloc
与非pod对象一起使用。你可能会偶尔侥幸逃脱,但你基本上是指着一只装满霰弹枪的脚。
似乎我不一定在类/ struct
中设置向量的初始大小
您可以轻松设置类中向量的默认大小,需要C ++ 11(gnu / clang编译器为realloc
或更高版本,VS2013或更高版本)
-std=c++11