“我们通常会使用
new
和 delete
,但在这里我使用 malloc
和 free
。这是必需的,因为某些编译器在使用 new
时会以不同的方式填充数据,导致在不同平台之间传输数据时出现错误。这不会发生在使用 malloc
中。”这与我从标准的
new
vs malloc
问题中所知道的任何内容都不符合。“”是一个非常流行的问题,但只涉及到
new
使用构造函数而 malloc
不使用,这与此无关。“
new
和 delete
,但在这里我使用 malloc
和 free
。这是必需的,因为某些编译器在使用 new
时会以不同的方式填充数据,导致在不同平台之间传输数据时出现错误。这不会发生在使用 malloc
中。” new
vs malloc
问题中所知道的任何内容都不符合。 new
使用构造函数而 malloc
不使用,这与此无关。malloc
保证返回任何标准类型对齐的地址。而::operator new(n)
仅保证返回任何标准类型对齐的地址不大于n,如果T
不是字符类型,则只需要为T
对齐即可,new T[n]
也是如此。malloc(sizeof(Foo) * n)
与new Foo[n]
之间的简单差异。也许更像:malloc((sizeof(int) + sizeof(char)) * n);
对比。
struct Foo { int a; char b; }
new Foo[n];
也就是说,他可能在说“我使用malloc”,但实际上意思是“我手动将数据打包到不对齐的位置,而不是使用结构体”。实际上,为了手动打包结构体,不需要使用malloc
,但没有意识到这一点是一种较小程度的混淆。必须定义发送到网络的数据布局。当使用结构体时,不同的实现会以不同的方式填充数据。
new[]/delete[]
的魔术数字(这是实现在删除数组时使用的信息)。但是,如果使用从new[]
返回的地址开始的分配(而不是分配器的地址),这将不会成为问题。
打包似乎更有可能。 ABI的变化可能会导致结构体末尾添加不同数量的尾随字节(这受对齐方式的影响,也考虑数组)。使用malloc,可以指定结构体的位置,因此更容易移植到外部ABI。通常通过指定传输结构的对齐和打包来防止这些变化。我认为你是正确的。填充是由编译器完成的,而不是new
或malloc
。即使您声明一个数组或结构体而不使用new
或malloc
,填充考虑仍然适用。无论如何,虽然我可以看到不同实现的new
和malloc
可能会在平台之间移植代码时引起问题,但我完全没有看到它们如何会导致在平台之间传输数据时出现问题。
new
只是malloc
的一个不错的封装,但从其他答案中看来,这并不完全正确。一致的意见似乎是无论使用哪种方式,填充应该是相同的;我认为在平台之间传输数据的问题只有在传输机制有缺陷时才会出现 :) - hcarver一个对象的布局不应该依赖于它是使用 malloc
还是 new
分配的。这两种方法都返回相同类型的指针,当你将这个指针传递给其他函数时,它们不会知道对象是如何分配的。 sizeof *ptr
只与 ptr
的声明有关,而不是它如何被赋值。
myclass *my = new myclass();
或者
int *i = new int(2);
但在所有情况下,您需要定义的数据类型(类、结构体、联合体、int、char等)并且只会分配所需对象/变量的字节内存(即该数据类型的倍数)。
但在使用malloc()方法时,您可以分配任意字节的内存,并且不必始终指定数据类型。在这里,您可以观察到malloc()的几种可能性:
void *v = malloc(23);
或者
void *x = malloc(sizeof(int) * 23);
或者
char *c = (char*)malloc(sizeof(char)*35);
这是我猜测这个问题来自何处的野猜想。正如你所提到的,问题在于通过MPI传输数据。
就我个人而言,为了发送/接收MPI上的复杂数据结构,我总是实现序列化/反序列化方法将整个结构打包/解包到一个字符数组中。现在,由于填充,我们知道该结构的大小可能大于其成员的大小,因此还需要计算数据结构的未填充大小,以便我们知道正在发送/接收多少字节。
例如,如果您想使用上述技术在MPI上发送/接收 std::vector<Foo> A
,通常假定生成的字符数组的大小为 A.size()* sizeof(Foo)
是错误的。换句话说,每个实现序列化/反序列化方法的类也应该实现一种报告数组大小的方法(或更好的是将数组存储在容器中)。这可能成为错误的原因。然而,这与本线程中指出的 new
vs malloc
没有任何关系。
当我想控制我的普通数据结构的布局时,我使用MS Visual编译器中的#pragma pack(1)
。我想这样的预编译指令被大多数编译器支持,例如gcc。
这会导致结构体中的所有字段一个接一个地对齐,没有空格。
如果另一端的平台也这样做了(即使用填充1编译其数据交换结构),那么在两端检索的数据就可以很好地适配。 因此,我从来没有必要在C++中使用malloc。
最坏的情况下,我会考虑重载new运算符,使其执行某些巧妙的操作,而不是直接在C++中使用malloc。
#pragma pack
或类似功能的编译器?我意识到这不会成为标准的一部分。 - hcarvermalloc是C++中的一种函数类型,而new则是一种数据类型。如果我们在C++中使用malloc,则必须使用类型转换,否则编译器会报错。但是,如果我们使用new数据类型来分配内存,则无需进行类型转换。
malloc
和new
而异,在某些环境中,new
分配一个块,在开头添加一些数据,并返回指向此数据右侧位置的指针。(我同意其他人的观点,在数据块内,malloc
和new
必须使用相同类型的填充。) - Lindydancer