如果“u heapchk()返回”,是否可以假定堆没有损坏;好吧;? 在VisualC++中,使用 NeX[]/CODE分配对象数组,然后默认缺省值>代码>删除> /代码>(不是删除[]/COD> >)。 所有对象调用析构函数需要知道对象的数量,因此VisualC++调用“代码>::运算符new []())/>代码分配一个稍微大一些的缓冲区,将元素的数量放在开始,然后调用构造函数并返回指向第一个对象的指针。当删除完成时,它只会销毁第一个对象,然后将错误的指针传递到::operator delete(),默认情况下,该操作的实现方式与::operator delete[]()完全相同

如果“u heapchk()返回”,是否可以假定堆没有损坏;好吧;? 在VisualC++中,使用 NeX[]/CODE分配对象数组,然后默认缺省值>代码>删除> /代码>(不是删除[]/COD> >)。 所有对象调用析构函数需要知道对象的数量,因此VisualC++调用“代码>::运算符new []())/>代码分配一个稍微大一些的缓冲区,将元素的数量放在开始,然后调用构造函数并返回指向第一个对象的指针。当删除完成时,它只会销毁第一个对象,然后将错误的指针传递到::operator delete(),默认情况下,该操作的实现方式与::operator delete[]()完全相同,c++,visual-c++,memory-management,undefined-behavior,C++,Visual C++,Memory Management,Undefined Behavior,如果出现以下情况: class Class { public: ~Class() { Sleep( 0 );} }; delete new Class[1]; 在版本配置中编译,并在调试器下运行。程序以断点停止: ntdll.dll!_DbgBreakPoint@0() ntdll.dll!_RtlpBreakPointHeap@4() + 0x28 bytes ntdll.dll!_RtlpValidateHeapEntry@12() + 0x113 bytes

如果出现以下情况:

class Class {
public:
   ~Class() { Sleep( 0 );}
};

delete new Class[1];
在版本配置中编译,并在调试器下运行。程序以断点停止:

ntdll.dll!_DbgBreakPoint@0()    
ntdll.dll!_RtlpBreakPointHeap@4()  + 0x28 bytes 
ntdll.dll!_RtlpValidateHeapEntry@12()  + 0x113 bytes    
ntdll.dll!_RtlDebugFreeHeap@12()  + 0x97 bytes  
ntdll.dll!_RtlFreeHeapSlowly@12()  + 0x246cf bytes  
ntdll.dll!_RtlFreeHeap@12()  + 0x17646 bytes    
sample.exe!free(void * pBlock=0x0003339c)  Line 110 C
sample.exe!main()  Line 48  C++
sample.exe!__tmainCRTStartup()  Line 266 + 0x12 bytes   C
kernel32.dll!_BaseProcessStart@4()  + 0x23 bytes
这看起来像堆损坏-至少这是我在本例中所期望的

我试着在那行之前和之后调用,但令人惊讶的是,它两次都返回
\u HEAPOK
。当程序结束时,也不会报告泄漏


如果
\u heapchk()
返回
\u HEAPOK
,我是否可以假设堆是完整的?

否,\u heapchk返回\u HEAPOK仅仅意味着它找不到问题或者堆不支持验证


我想说的是,当您出现此错误时,更有可能是删除了未初始化的指针。

否,\u heapchk returning\u HEAPOK仅仅意味着它找不到问题或堆不支持验证


我想说的是,当出现此错误时,更有可能是删除了未初始化的指针。

我不能肯定,但我已经对此进行了一些研究,并注意到两件事:

  • 在发布版本中,编译器有时会将程序集调用放到“操作符删除”中,即使C++代码使用常规的删除。
  • 在发布版本中,当使用错误的delete时,CRT会识别不匹配,并通过RtlpLogHeapFailure报告它(天知道这意味着什么…)
  • 我只是在猜测,但我的猜测是,delete中处理堆的部分比您想象的要聪明。它实际上有一种方法来识别你发送的内容,并据此进行处理。因此,在调试构建时,您将从其他调试测试中获得一个断言,但在较低级别上,堆仍然可以保护自己,并执行正确的操作,而不会损坏。如果真的是这样,在VC++上,删除的类型只会影响破坏,堆的部分是正确的。其他编译器的行为可能不同


    这就是为什么_heapchk()不会返回失败…

    我不能肯定,但我已经玩了一点,注意到两件事:

  • 在发布版本中,编译器有时会将程序集调用放到“操作符删除”中,即使C++代码使用常规的删除。
  • 在发布版本中,当使用错误的delete时,CRT会识别不匹配,并通过RtlpLogHeapFailure报告它(天知道这意味着什么…)
  • 我只是在猜测,但我的猜测是,delete中处理堆的部分比您想象的要聪明。它实际上有一种方法来识别你发送的内容,并据此进行处理。因此,在调试构建时,您将从其他调试测试中获得一个断言,但在较低级别上,堆仍然可以保护自己,并执行正确的操作,而不会损坏。如果真的是这样,在VC++上,删除的类型只会影响破坏,堆的部分是正确的。其他编译器的行为可能不同

    这就是为什么_heapchk()不会返回失败…

    来自(强调我的):

    \u heapchk
    函数通过检查堆的最小一致性来帮助调试与堆相关的问题

    它不会检查绝对的一致性和正确性:它应该能够检测出严重的错误,但它不会捕捉到每一个错误。

    来自(我的重点):

    \u heapchk
    函数通过检查堆的最小一致性来帮助调试与堆相关的问题


    它不会检查绝对的一致性和正确性:它应该能够检测重大的异常错误,但它不会捕获所有错误。

    您的意思是,您在调用未定义的行为后调用函数,但仍然希望信任结果?;-)

    在这里,我只是猜测,未定义的行为可以在很多方面表现出来,最常见的是“似乎有效”。惊讶

    其他异常情况包括:
    -在同一语句中调用new和delete。
    -您只分配一个元素。
    -在整个程序中,您只能在一个位置执行此操作。
    -析构函数对内存分配没有任何重要作用。

    所有这些都会影响优化器生成代码的方式,正如eran所说,编译器可以很容易地看到所有这些并了解您正在做什么。这并不愚蠢

    您的意思是,您在调用未定义的行为后调用了函数,但仍然希望信任结果?;-)

    在这里,我只是猜测,未定义的行为可以在很多方面表现出来,最常见的是“似乎有效”。惊讶

    其他异常情况包括:
    -在同一语句中调用new和delete。
    -您只分配一个元素。
    -在整个程序中,您只能在一个位置执行此操作。
    -析构函数对内存分配没有任何重要作用。
    所有这些都会影响优化器生成代码的方式,正如eran所说,编译器可以很容易地看到所有这些并了解您正在做什么。这并不愚蠢