Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/136.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++内存泄漏——需要同行评审_C++_Memory Leaks - Fatal编程技术网

C++内存泄漏——需要同行评审

C++内存泄漏——需要同行评审,c++,memory-leaks,C++,Memory Leaks,我的截图代码中有一个很大的漏洞 我的C++很糟糕,所以如果有人能指出那些非常奇妙的问题! 以下是违规代码: FString AWindow::CaptureWindow(HWND hwnd) { HDC hdcSrc = GetWindowDC(hwnd); RECT rawRect; LPRECT rect = &rawRect; GetWindowRect(hwnd, rect); int width = rect->right - rect->left; int

我的截图代码中有一个很大的漏洞

<>我的C++很糟糕,所以如果有人能指出那些非常奇妙的问题! 以下是违规代码:

FString AWindow::CaptureWindow(HWND hwnd) {

HDC hdcSrc = GetWindowDC(hwnd);
RECT rawRect;
LPRECT rect = &rawRect;

GetWindowRect(hwnd, rect);

int width = rect->right - rect->left;
int height = rect->bottom - rect->top;

HDC hdcDest = CreateCompatibleDC(hdcSrc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdcSrc, width, height);

HGDIOBJ h0ld = SelectObject(hdcDest, hBitmap);
BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY);
SelectObject(hdcDest, h0ld);
DeleteDC(hdcDest);

    char* pImage = NULL;
    pImage = (char*)GlobalLock(hBitmap);


BITMAP bmp;
PBITMAPINFO pbmi;
WORD cClrBits;

GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bmp);

//Convert the color format to a count of bits
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);

if (cClrBits == 1)
    cClrBits = 1;
else if (cClrBits <= 4)
    cClrBits = 4;
else if (cClrBits <= 8)
    cClrBits = 8;
else if (cClrBits <= 16)
    cClrBits = 16;
else if (cClrBits <= 24)
    cClrBits = 24;
else cClrBits = 32;

//Allocate memory for the BITMAPINFO structure.
if (cClrBits < 24) {
    pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1i64 << cClrBits));
}
else {
    pbmi = (PBITMAPINFO)LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
}

//Initialize the field in the BITMAPINFO structure
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biClrUsed = (1i64 << cClrBits);

pbmi->bmiHeader.biCompression = BI_RGB;

//Computer the number of bytes in the array of color
//indices and store the result in biSizeImage.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits + 31) & ~31) / 8
    * pbmi->bmiHeader.biHeight;

//Set biClrImportant to 0, indicating that all of the device
//colors are important
pbmi->bmiHeader.biClrImportant = 0;

FString file = FPaths::Combine(*FPaths::GameDir(), TEXT("ScreenGrab/"), TEXT("Desktop.bmp"));

std::string mystring(TCHAR_TO_UTF8(*file));
std::wstring lpstring = std::wstring(mystring.begin(), mystring.end());
LPCWSTR realfile = lpstring.c_str();

FString error = CreateBMPFile(hwnd, realfile, pbmi, hBitmap, hdcSrc);

ReleaseDC(hwnd, hdcSrc);
DeleteObject(hBitmap);
return error;
}


再次感谢您的帮助!为解决这一混乱局面的任何人准备的数字布朗尼

pbmi是本地分配的

您忘记使用LocalFree来释放分配

可能还有更多,但这是我发现的第一个。

使用资源获取是初始化模式,您不必在每次返回之前都进行关闭和释放。此外,如果引发异常(例如UTF8翻译中的错误字符编码),您将防止泄漏。以下是@JesperJuhl在代码上下文中所指的习惯用法:

using file_raii_t = std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)>;
using gmem_raii_t = std::unique_ptr<std::remove_pointer<HGLOBAL>::type, decltype(&::GlobalFree)>;

gmem_raii_t gmem(::GlobalAlloc(GMEM_FIXED, size), ::GlobalFree);
// gmem can be used like (!GetDIBits(..., gmem.get(), ...);

file_raii_t fh(::CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD)0, NULL,
    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL), ::CloseHandle);
//fh can be used like FileRead(fh.get()...);
这可以扩展到包括其他API,甚至包括作为out参数返回资源的API。在您的例子中:GetWindowDC,LocalAlloc。使用RAII,您可以编写更少的异常安全代码行


注意:代码来自我老化的记忆。未在代码中测试。

谢谢!改变了!实际上,我将严重泄漏的范围缩小到了CreateBMPFile,我正在文章底部的编辑中添加该文件。介意看一下吗?这个函数会被连续调用一整串,并快速地将MB的内存分配到MB。在每次返回之前,您需要全局释放内存,这会节省大量内存。只需确保你不会有两次空闲。哦,还有一件事,在每次返回之前使用CloseHandle-把手将保持打开状态,这会导致泄漏。谢谢!我读了你的回复,把它全部看了一遍。找到了罪魁祸首,并用其他更改更新了我的代码,我需要在每次返回之前释放HP。尽管hp是指向全局alloc的,但它仍在使用智能指针和自定义删除程序来释放和关闭您的资源。这样你就不用到处手动管理了。顺便说一句,这个问题更适合于哦,我不知道codereview是一个东西。我想知道为什么所有的人都投了反对票。我不确定智能指针与虚幻引擎的兼容性如何,但我会在前进的过程中记住它们:@JesperJuhl Bjarne会为你的RAII评论感到骄傲:注意:GlobalAlloc和CreateFile需要RAII.TCHAR_到_UTF8*文件,这没有意义。您应该在Windows中使用UTF16。例如std::wstring s=Lc:\\temp\\filename.bmp;你不需要在这里进行任何转换。
using file_raii_t = std::unique_ptr<std::remove_pointer<HANDLE>::type, decltype(&::CloseHandle)>;
using gmem_raii_t = std::unique_ptr<std::remove_pointer<HGLOBAL>::type, decltype(&::GlobalFree)>;

gmem_raii_t gmem(::GlobalAlloc(GMEM_FIXED, size), ::GlobalFree);
// gmem can be used like (!GetDIBits(..., gmem.get(), ...);

file_raii_t fh(::CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD)0, NULL,
    CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL), ::CloseHandle);
//fh can be used like FileRead(fh.get()...);