【发布时间】:2021-10-13 02:50:51
【问题描述】:
我正在开发一个基于 COM 的 C++ 项目,我的代码有一个带有 out 参数的函数,该函数将一个对象作为输入并将一个类的新实例分配给它。但是当我使用 CRT Debugging 时,我发现函数中有一些内存泄漏,这里是函数的代码。
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
if (compositionHost != nullptr)
{
*compositionHost = reinterpret_cast<ICompositionHost*>(new CompositionHost(hwnd));
if (compositionHost != nullptr)
{
return true;
}
}
else
{
return false;
}
return false;
}
此函数接受ICompositionHost 的对象并使用CompositionHost 对象对其进行初始化,我应该在哪里释放内存以避免内存泄漏。
我使用 ComPtr 调用函数,但仍然存在内存泄漏
ComPtr<ICompositionHost> host;
compositor->CreateCompositionHost(hwnd,host.GetAddressOf());
完整代码:
FluentCompositor.cpp
#include "pch.h"
#include "ICompositionHost.h"
#include "IFluentCompositor.h"
#include "CompositionHost.h"
#include "FluentCompositor.h"
FluentCompositor::FluentCompositor() :ref(1)
{
}
ulong __stdcall FluentCompositor::AddRef()
{
return (++ref);
}
ulong __stdcall FluentCompositor::Release()
{
if (--ref == 0)
{
delete this;
return 0;
}
return ref;
}
HRESULT __stdcall FluentCompositor::QueryInterface(REFIID iid, LPVOID* ppv)
{
if (iid == IID_IFluentCompositor || iid == IID_IUnknown)
{
*ppv = (void*)this;
AddRef();
}
else
{
*ppv = NULL;
}
return (*ppv == NULL) ? E_NOINTERFACE : S_OK;
}
HRESULT __stdcall CreateFluentCompositor(void** compositor)
{
if (compositor != nullptr)
{
*compositor = reinterpret_cast<void*>(new FluentCompositor());
if (compositor != nullptr)
{
return S_OK;
}
}
else
{
return E_INVALIDARG;
}
return E_FAIL;
}
bool __stdcall FluentCompositor::CreateCompositionHost(HWND hwnd, ICompositionHost** compositionHost)
{
if (compositionHost != nullptr)
{
*compositionHost = reinterpret_cast<ICompositionHost*>(new CompositionHost(hwnd));
if (compositionHost != nullptr)
{
return true;
}
}
else
{
return false;
}
return false;
}
MainWindow.cpp
#include "pch.h"
#include "MainWindow.h"
int __stdcall wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int)
{
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
const wchar_t className[] = L"Fluent Compositor";
WNDCLASS wc = {
.lpfnWndProc = WndProc,
.hInstance = reinterpret_cast<HINSTANCE>(&__ImageBase),
.hCursor = LoadCursor(nullptr, IDC_ARROW),
.lpszClassName = className,
};
RegisterClass(&wc);
HWND hwnd = CreateWindowEx(WS_EX_NOREDIRECTIONBITMAP, className, L"Fluent Compositor Sample", WS_OVERLAPPEDWINDOW | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, wc.hInstance, nullptr);
if (hwnd == nullptr)
{
return 0;
}
CreateCompositionEffect(hwnd);
MSG msg = { };
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
_CrtDumpMemoryLeaks();
return 0;
}
bool CreateCompositionEffect(HWND hwnd)
{
auto fluentCompositorLib = LoadLibrary(L"FluentCompositor.dll");
if (!fluentCompositorLib)
{
return false;
}
CreateCompositor = (CreateFluentCompositor)GetProcAddress(fluentCompositorLib, "CreateFluentCompositor");
if (!CreateCompositor)
{
return false;
}
CreateCompositor(&compositor);
if (compositor == nullptr)
{
return false;
}
ComPtr<ICompositionHost> host;
compositor->CreateCompositionHost(hwnd,&host);
return true;
}
LRESULT __stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hwnd, msg, wparam, lparam);
}
MainWindow.h
#pragma once
#include "IFluentCompositor.h"
using namespace Microsoft::WRL;
extern "C" IMAGE_DOS_HEADER __ImageBase;
ComPtr<IFluentCompositor> compositor;
typedef BOOL(__stdcall* CreateFluentCompositor)(IFluentCompositor** compositor);
CreateFluentCompositor CreateCompositor;
bool CreateCompositionEffect(HWND hwnd);
LRESULT __stdcall WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
【问题讨论】:
-
您应该在停止使用内存时释放内存。似乎您不想破坏此函数中的对象,因此泄漏的问题在其他地方,更具体地说,
compositionHost超出范围 -
但我将 ComPtr
对象作为参数传递给函数,所以 ComPtr 释放它对吗? -
ICompositionHost似乎是一个 COM 接口。 COM 接口是引用计数的。当引用计数达到零时,您释放实现该接口的对象。这是(大概)在CompositionHost中实现的。要取得进展,您必须停止思考错误:您的函数不 “采用ICompositionHost的对象”。它接收指向ICompositionHost接口的指针的地址。 -
内存泄漏是您最少的问题。您需要解决更严重的问题。就像使用 C++ 的分配器到 move memory across DLL boundaries。或者盲目地让 C++ 异常跨越 ABI 边界。或者没有正确报告错误,只是留下一个未初始化的
[out]参数。就像,有很多错误,甚至很难弄清楚从哪里开始。 -
是
CompositionHost你的吗?例如,你是否正在实施它?如果是这样,您的IUnknown实现是否正确管理了引用计数,或者您是否使用 ATL 工具包类来为您处理? COM 接口引用计数不是火箭科学,但它很容易搞砸,因为它是正确的。还。如果您在 samehost智能指针实例上调用CreateCompsitionHost方法多个而没有中间Release您绝对会泄漏内存,因为任何先前的接口指针都是托管将不会正确发布。
标签: c++ oop winapi visual-c++ interface