C++默认参数通过_CrtMemDifference屏蔽内存泄漏检测
C++ default argument masks memory leak detection via _CrtMemDifference
长期读者,第一次提问者。
我正在使用Visual Studio 2013中的Microsoft单元测试框架编写单元测试。我正在使用此答案 https://stackoverflow.com/a/2981185/4446293 中描述的内存泄漏检测代码的变体,效果很好。但是,我想命名 CrtCheckMemory 的每个实例,以便清楚地识别产生泄漏的测试用例,并提供默认测试名称。这是我的测试用例的完整源代码:
#include "stdafx.h"
#include "CppUnitTest.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
#include <string>
#include <ostream>
#include <crtdbg.h>
// A default test name, allocated statically so as to definitely not affect the heap.
static const char* UNNAMED_TEST = "Unnamed Test";
// Instances of this struct should detect heap differences that occur
// while they are in scope.
struct CrtCheckMemory {
_CrtMemState state1, state2, state3;
const char* tname;
// Allowing this default argument to be used seems to
// mask this class's ability to see heap changes.
CrtCheckMemory(const char* testName = UNNAMED_TEST) : tname(testName) {
_CrtMemCheckpoint(&state1);
}
~CrtCheckMemory() {
_CrtMemCheckpoint(&state2);
if (_CrtMemDifference(&state3, &state1, &state2)) {
std::ostringstream oss; oss << "MEMORY LEAK DETECTED in " << tname << "- see Debug output for details";
Logger::WriteMessage(oss.str().c_str());
_CrtMemDumpStatistics(&state3);
}
}
};
namespace TestLeakyCauldron
{
TEST_CLASS(UnitTest1)
{
public:
TEST_METHOD(DetectsALeak_Test) {
CrtCheckMemory checker("DetectsALeak");
malloc(1);
Logger::WriteMessage("You should see a MEMORY LEAK DETECTED message for test DetectsALeak");
}
TEST_METHOD(LeaksButNoMessage_Test) {
CrtCheckMemory checker();
malloc(1);
Logger::WriteMessage("You SHOULD see a MEMORY LEAK DETECTED message for test Unnamed Test, but you won't");
}
};
}
只要我实际向 CrtCheckMemory 构造函数提供一个名称,这就可以很好地工作。但是,如果我不提供名称,则不会检测到 CrtCheckMemory 对象在范围内时发生的泄漏(或者无论如何,不会向 VS2013 输出窗口的"测试"窗格发出"检测到内存泄漏"消息)。
我的问题是,为什么泄漏检测在一种情况下有效,而在另一种情况下无效?
我不明白为什么提供一个仅是静态分配的指针值的默认参数会改变 CRT 堆的状态。我猜这与 _CrtMemCheckpoint() 和 _CrtMemDifference() 实现的内部有关。但是我是否错过了一些关于 ctor 的默认参数如何工作的重要内容?在两种不同的 ctor 情况下,我没有看到任何堆活动的机会(默认参数与显式参数)。
注意:我最初使用 std::string成员来保存 CrtCheckMemory 类中的测试名称,但我改为使用 const string* 和字符串文字,以避免 std::string 构造函数和析构函数以 _CrtMemCheckpoint() 可见的方式更改堆状态的可能性。
发现了问题,这基本上是我花在 Java 上的时间比现在花在 Java 上的时间比C++多。
CrtCheckMemory crtcm();
不是使用默认 CTOR 声明实例的正确方法。那将是:
CrtCheckMemory crtcm;
正如Hans Passant指出的那样,这是C++"最令人烦恼的解析":Visual C++接受"不正确"的声明,因为它是不接受任何参数并返回CrtCheckMemory的函数的正确decl。它确实发出了我以前忽略的警告(C4930)。使用错误的 decl 时不会报告泄漏,因为在测试范围内实际上没有创建 CrtCheckMemory 实例。更正此问题会导致预期的泄漏检测消息。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 如何取消对nullptr的屏蔽,返回正确的对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何针对特定情况调试和修复此双自由内存损坏问题
- C++默认参数通过_CrtMemDifference屏蔽内存泄漏检测
- 如何将字符串内存地址(如 "7fefe05a8")存储在 C++ 中的指针/int 变量中,以便我可以对其进行位屏蔽?