当我们在C / C ++中定义动态数组时,它使用头段来跟踪数组中的元素数量(在堆中)。 例如:
int* mem = new int[8];
编译器将分配sizeof(int)* 8个字节。
int *temp = malloc(sizeof(int)*9)
将存储" 8"在第一个sizeof(int)字节中,它就像这样
*temp = 8;
然后设置 mem 地址,其下一个连续地址是 temp
mem = temp + 1;
因此, mem 将指向包含8个元素的数组,而不是9个。
当删除发生时,编译器将在上面的反向过程中使用 mem 来释放该堆块中的内存
delete[] mem;
我的问题是
如果我们在运行时分配将在不同模块中使用的动态内存,并且我们设法使用分配的堆内存的头部分来检索元素数量,那么在多线程环境中使用是否安全?
(请假设在每个模块中通过程序设计,没有提供帮助函数或属性来检索定义的动态数组中的元素数量(大小)。每个模块只传递地址(指针)到数组但不是它的大小)
答案 0 :(得分:3)
不,在任何环境下都不安全。您不能依赖编译器在分配的内存之前存储数组中的元素数,因为它不是定义的行为。你永远不应该试图达到这个价值。
相反,甚至不使用动态数组,而是选择std::vector
。
答案 1 :(得分:1)
访问mem - 1
有未定义的行为。
编译器将......
如果你的目标是那个版本的编译器,只有那个版本,并且编译器供应商记录了这个行为,那么也许你可以相信编译器的版本确实如你所观察到的那样。
但依赖于它的程序对于其他编译器是不可移植的,可能是同一编译器的其他版本,也可能是使用相同编译器的相同版本的其他平台。
无论是多线程还是单线程都是如此。
如果我们在运行时分配将在不同模块中使用的动态内存,并且我们设法使用分配的堆内存的头部分检索元素数量,那么在多线程环境中使用是否安全?
在多线程程序中使用动态内存是安全的,因为使用任何内存都是安全的。当然,多线程意味着数据竞争的潜力。您必须将修改同步到可能被其他线程同时访问的任何对象。对象是否在动态内存中没有任何区别。
答案 2 :(得分:0)
我使用Visual Studio版本构建测试了这个:
int * mem = new int[8];
导致调用malloc等效于
int * mem = malloc(32); // 32 = 8 * sizeof(int)
整数数组的大小不存储在任何地方,(据我所知,包括malloc头,malloc头只有一些类型的链接/标志用于重新组合从堆中分配(并虚拟映射)的块)。
答案 3 :(得分:0)
使用未记录的系统信息原则上是不可能的,即使它似乎有效:它可能在意外情况下表现不同,并且无法保证可移植性,即使在同一制造商中也是如此。
如果您想要使用匹配,请确保在您读取大小和访问块的那一刻之间没有其他线程执行与内存分配相关的操作;你需要为此目的实现一个关键部分。