对包括stdvector的类/结构数组使用malloc/realloc
Using malloc/realloc for array of classes/structs including std vector
我有一个问题,wrt malloc/realloc内存将包含一个包含std向量的类/结构(我尝试了结构和类,问题仍然存在)成员数组。我知道我可以通过使用新的std数组容器类来规避这个问题。然而,我想更好地理解为什么当我使用realloc而不是malloc时,以下小代码会崩溃(因为我在将更大的代码项目从C转换到C++的过程中遇到了这个问题)。我似乎也不一定能在类/结构中设置向量的初始大小(有些编译器允许,有些则不允许)——那么类中的向量是什么——一个舒适的指针?
谢谢,Kai
#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 donen");
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc donen");
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
printf("realloc donen");
for(i=0;i<10;++i) Comp[i].y.push_back(d);
for(i=0;i<10;++i) printf("%lfn",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("%lfn",Comp2[i].y[0]);
return 1;
}
如果将malloc()
与非POD类一起使用,则必须手动调用构造函数(通过放置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);
请记住,上面的代码并不是真正的异常安全。如果一个构造函数抛出一个异常,并且您捕捉到了它,那么您需要确保正确地解构了所构造的对象谢谢@StevenJessop
现在,当您理解为什么在C++中通常应该避免malloc()
/free()
时,我希望您能回到更安全的new
/delete
,它为您完成所有的构建和破坏
这可能与realloc
无关。当你在接近开始时这样做时,你的代码已经有了未定义的行为:
for(i=0;i<10;++i) Comp[i] = v0;
Comp[0]
从未初始化过(因为malloc
返回未初始化的内存——它不知道你打算将其用于什么类型,所以即使它想初始化,也不可能初始化它)。然后您的代码尝试分配给它。这对于像vector
这样的复杂类型是不允许的。
为什么不允许?在向量的情况下,因为当您指定给已经包含数据的向量时,它需要释放旧数据。如果没有什么可以释放的,那么它就什么都不会释放。但是,未初始化的内存可能有任何值,所以在vector
看来,很可能有一些东西应该被释放,事实上,它根本不是一个可释放的指针,更不用说vector
应该因为该赋值而释放的东西了。在没有初始化的情况下,违反了一些类不变量,即"该指针数据成员始终是空指针,或者是向量负责的某个内存的地址",因此vector
代码不起作用。
假设您的代码以某种方式通过了这一点,那么您仍然无法使用包含vector
的realloc
内存。从标准的角度来看,这是因为vector<double>
不是POD类型,因此它的逐字节拷贝(包括realloc
所做的拷贝)会导致未定义的行为。
从一个特定实现的角度来看,我们可能会问自己,实现者可能会写什么代码,在矢量被逐字节复制的情况下,这会出错。一个假设的答案是,在某些情况下,vector
可以包含一个指向其自身的指针(作为所谓的小向量优化的一部分)[编辑:实际上,我认为由于其他原因,小向量优化在标准中是不可能的,但我的总体观点是,因为向量不是POD,所以实现者可以自由使用他们的创造力]。如果向量被重新定位,则该指针不再指向向量自身,因此类不变量不满足,代码也不再工作。为了让实现者可以自由地编写这样的代码,作为类的用户,您的自由度是有限的,并且不允许通过逐字节复制来重新定位向量(或者通常任何非POD类型)。
/* 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()
内存,你不能假设初始化的对象期望找到什么值。
/* dynamically re-allocate memory */
Comp2= (voxel*)malloc(sizeof(voxel));
printf("realloc donen");
Comp2现在是指向单个体素的指针,并且没有执行"realloc"。
for(i=0;i<10;++i){
Comp2 =(voxel*)realloc(&Comp2[0], (i+1)*sizeof(voxel));
Comp2[i] = v0;
}
这太奇怪了。它从Comp2指向单个体素开始。然后,出于某种原因,您采用第一个元素(&Comp2[0]
)的地址,而不是仅使用第一个元素的地址(Comp2
),并将其重新分配为相同的大小。然后将assign v0复制到除一个位置之外的最后一个未初始化的内存中:
Comp2 = [...uninit...]
for (i = 0
realloc(i + 1 == 1)
Comp2 = [...uninit...]
^-- v0
i++
realloc(i+1 == 2)
Comp2 = [.....v0.....][...uninit...]
^--v0
短:不能将malloc
、calloc
或realloc
与非pod对象一起使用。你可能偶尔会逃脱惩罚,但你基本上是在用一把上膛的猎枪指着你的脚。
我似乎也不一定能在类/结构中设置向量的初始大小
您可以很容易地设置类中向量的默认大小,C++11是必需的(对于gnu/clang编译器,VS2013或更高版本,-std=c++11
或更大)
#include <iostream>
#include <vector>
struct A {
std::vector<int> v = { 1, 2, 3 }; // default population
};
struct B {
std::vector<int> v;
B() : v(4) {}
};
int main() {
A a;
B b;
std::cout << a.v.size() << ", " << b.v.size() << "n";
std::cout << "n";
for (int v : a.v) { std::cout << v << "n"; }
std::cout << "n";
for (int v : b.v) { std::cout << v << "n"; }
}
http://ideone.com/KA9fWB
- 如果没有malloc,链表实现将失败
- malloc() 可能出现内存泄漏
- Cuda C++:设备上的Malloc类,并用来自主机的数据填充它
- 当我尝试加载内核模块时,如何修复C++中的这个 malloc() 错误?
- 在C++中创建队列 - 什么是 malloc 错误?
- 如何在 malloc 内存中初始化非 POD 数据
- 使用 malloc() 时出现意外大小
- C++:在被本地字符串捕获后释放或销毁 malloc'd char *?
- 错误:malloc:对象 0x7f9edf504080 的 *** 错误:未分配正在释放的指针
- 将 malloc 替换为数组
- SIGSEGV on Boost UDP 套接字关闭 - tcache_get at malloc.c.
- Realloc 两次无法在 Visual Studio 上运行
- C++malloc/realloc的奇怪行为
- Realloc():即使使用malloc()分配内存,旧大小也无效
- 如果Malloc无法分配X字节,我应该使用Realloc还是再次使用Malloc?C++
- c++ realloc performance vs malloc
- 在std::string上使用malloc/realloc/free时出现c++内存错误
- realloc和calloc调用malloc吗?
- 对包括stdvector的类/结构数组使用malloc/realloc
- 被释放的指针没有在构造函数中分配 realloc 和 malloc