C++ 是否可以将内存段标记为;“禁止入内”;因此堆管理器不会';你不能从中分配吗?
今天早些时候我问 在花了一些时间调查这个问题之后,我发现了正在发生的事情。我将此作为一个新问题发布,因为我认为它足够有趣,可以作为一个单独的问题进行跟踪。我将用答案更新这个问题(以及这个问题的链接) 从调试器启动单元测试C++ 是否可以将内存段标记为;“禁止入内”;因此堆管理器不会';你不能从中分配吗?,c++,unit-testing,dynamic-memory-allocation,heap-memory,C++,Unit Testing,Dynamic Memory Allocation,Heap Memory,今天早些时候我问 在花了一些时间调查这个问题之后,我发现了正在发生的事情。我将此作为一个新问题发布,因为我认为它足够有趣,可以作为一个单独的问题进行跟踪。我将用答案更新这个问题(以及这个问题的链接) 从调试器启动单元测试 // Construct object Object* pObject = new Object(...); // Pointer value of pObject == 0x05176960 // Lots of other code // ... // Destroy
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05560194 /* Different memory location */
从命令行启动单元测试
// Construct object
Object* pObject = new Object(...);
// Pointer value of pObject == 0x05176960
// Lots of other code
// ...
// Destroy object
delete pObject;
// Construct object again
pObject = new Object(...);
// Pointer value of pObject == 0x05176960 /* Same memory location */
总之:
- 从命令行启动单元测试时,后续调用
以分配new
对象
(
在分配新对象之前删除前一个delete
对象)始终在内存中返回相同的地址
- 从调试器启动单元测试时,后续调用
以分配new
(对象
在分配新对象之前删除之前的delete
对象)始终在内存中返回唯一地址
Object
的分配总是在内存中获得相同的地址,因此我正在访问的存储了旧指针的映射仍然可以使用,并且测试不会崩溃。但是我希望我的单元测试在缺陷修复不到位时崩溃,以确保它不会悄悄地失败,并且缺陷不会再次出现
我的问题分为两部分:
1执行此操作的一个明显方法是不删除原始对象,但分配此对象的代码部分在我的生产代码中,我这样做会导致内存泄漏。这是一个未定义行为的示例。无论是C++还是堆管理器都不知道如何分配内存。您不能依赖内存被重用或不被重用。执行上述操作时,无法确定或更改返回的指针是否与第一个分配的指针不同。这是未定义行为的示例。无论是C++还是堆管理器都不知道如何分配内存。您不能依赖内存被重用或不被重用。当你像上面那样做的时候,无法确定或更改返回的指针是否与第一个分配的指针不同。您可以使用具有所需行为的自己版本替换
新建和删除。您可以使用具有所需行为的自己版本替换新建和删除您想要的行为。您的单元测试是有缺陷的,因为它依赖于未定义的行为。您应该重写单元测试,使其不依赖于未定义的行为,在这种情况下,无论内存管理器决定如何分配内存,单元测试都将通过
您正在做的是:
Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed
您应该重新构造单元测试,使其工作方式如下:
Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it. If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests
您的单元测试是有缺陷的,因为它依赖于未定义的行为。您应该重写单元测试,使其不依赖于未定义的行为,在这种情况下,无论内存管理器决定如何分配内存,单元测试都将通过
您正在做的是:
Object* pObject = new Object(...);
...
delete pObject;
pObject = new Object(...);
// Use dangling pointer to first object, and if it crashes, the unit test fails
// This is WRONG since a crash isn't guaranteed
您应该重新构造单元测试,使其工作方式如下:
Object* pObject = new Object(...);
...
// Check to see if there are dangling references to pObject right before we
// delete it. If there are, assert() and fail the unit test.
assert(NoDanglingReferences(pObject));
delete pObject;
// Continue on with more tests
首先-不在“正常”内存管理器中。释放内存后,您将其所有权传递给内存管理器,后者可以重用它
你可以按照建议去做,但它会做什么呢?它不是从空中制造内存,而是从CRT堆或操作系统堆之类的地方请求内存
场景A。它不会将内存返回到底层堆-您将有一个泄漏,内存块仍将映射到地址空间,并且可以访问
场景B。它会将内存返回到底层堆-然后,当管理者尝试再次分配内存时,底层堆可以再次返回该块。而且,当您将内存返回到底层堆时,您不知道它会做什么。它可能会使其未映射或不映射-因此访问内存可能会崩溃或不崩溃
底线是你完蛋了。尝试测试未定义的行为不会很有成效。首先,在“正常”内存管理器中不会。释放内存后,您将其所有权传递给内存管理器,后者可以重用它
你可以按照建议去做,但它会做什么呢?它不是从空中制造内存,而是从CRT堆或操作系统堆之类的地方请求内存
场景A。它不会将内存返回到底层堆-您将有一个泄漏,内存块仍将映射到地址空间,并且可以访问
场景B。它会将内存返回到底层堆-然后,当管理者尝试再次分配内存时,底层堆可以再次返回该块。而且,当您将内存返回到底层堆时,您不知道它会做什么。它可能会使其未映射或不映射-因此访问内存可能会崩溃或不崩溃
底线是你完蛋了。尝试测试未定义的行为不会有很大成效。同意,我的测试依赖于未定义的行为。实际上,它做它需要做的事情,并且(基于我100次的样本量),它总是在需要的时候中止。你可以:1/typedef指向另一个类型的指针(shared_ptr),2/重载操作符t的地址