Странная утечка памяти

290
15 ноября 2017, 01:17

Я знаю место где она может быть, но что бы я не пробовал применить туда, утечка не пропадает.

Происходит в методе resize() где производится перерасчет rect для отрисовки текста, при всем при этом я уже было подумал сделать отдельный класс для управления указателями, т.к. ни один из указателей из библиотеки std не помог.

Вот сам кусок кода в котором по моему мнению происходит утечка:

void graphics::resize()
{
    IDWriteTextLayout* layout;
    GetClientRect(window_handle_, &window_rect_);
    InvalidateRect(window_handle_, &window_rect_, false);
    HRESULT result = dwrite_factory_->CreateTextLayout(copy_of_str_.c_str(),
        copy_of_str_.length(),
        dw_text_format_,
        window_rect_.right - window_rect_.left,
        window_rect_.bottom - window_rect_.top, reinterpret_cast<IDWriteTextLayout**>(&layout));
    check_hr(result);
    result = hwnd_render_target_->Resize(D2D1::SizeU(window_rect_.right - window_rect_.left,
                                                     window_rect_.bottom - window_rect_.top));
    DWRITE_TEXT_METRICS met;
    layout->GetMetrics(&met);
    metrycs_ = met;
    if (FAILED(result))
    {
        _com_error err = result;
        MessageBoxW(window_handle_, err.ErrorMessage(), L"Error", MB_OK | MB_ICONERROR);
        return;
    }
    std::wstringstream string_stream;
    string_stream << L"Client size — Width: " << window_rect_.right - window_rect_.left << ", Height: " << window_rect_.
        bottom - window_rect_.top;
    copy_of_str_ = string_stream.str();
    render();
    layout->Release();
}

Так же ниже приведу полный код класса.

#pragma once
#include <d2d1.h>
#include <dwrite.h>
#include <map>
#include <string>
#include "button_base.h"
class graphics
{
public:
    struct dpi_data { float x; float y; };
private:
    gui::button_base* button_;
    ID2D1Factory* factory_;
    ID2D1HwndRenderTarget* hwnd_render_target_;
    ID2D1RenderTarget* render_target_;
    IDWriteTextLayout* dwrite_text_layout_;
    IDWriteTextFormat* dw_text_format_;
    IDWriteFactory* dwrite_factory_;
    ID2D1SolidColorBrush* black_brush_;
    HWND window_handle_;
    RECT window_rect_;
    dpi_data current_dpi_data_;
    std::map<std::wstring, IDWriteTextFormat*> fonts_;
    static bool check_hr(HRESULT hr);
    DWRITE_TEXT_METRICS metrycs_;
    std::wstring copy_of_str_;
public:
    graphics();
    ~graphics();
    bool init(HWND hwnd);
    void begin_draw() const;
    void end_draw() const;
    void render();
    IDWriteTextFormat* get_text_format(std::wstring font_name);
    void draw_text(std::wstring font_name, std::wstring text, int x, int y) const;
    void resize();
    dpi_data get_dpi_data();
};
#include "graphics.h"
#include <comdef.h>
#include <locale>
#include <vector>
#include <algorithm>
#include <sstream>
#include <memory>
bool graphics::check_hr(HRESULT hr)
{
    if (FAILED(hr))
    {
        _com_error err = hr;
        MessageBoxW(nullptr, err.ErrorMessage(), L"Error", MB_OK | MB_ICONERROR);
        return false;
    }
    return true;
}
graphics::graphics() : button_(nullptr), factory_(nullptr), hwnd_render_target_(nullptr), render_target_(nullptr),
                       dwrite_text_layout_(nullptr), dw_text_format_(nullptr),
                       dwrite_factory_(nullptr),
                       black_brush_(nullptr), window_handle_(nullptr)
{
    window_rect_ = {0,0,0,0};
}
graphics::~graphics()
{
    if (black_brush_)
    {
        black_brush_->Release();
        black_brush_ = nullptr;
    }
    if (factory_)
    {
        factory_->Release();
        factory_ = nullptr;
    }
    if (hwnd_render_target_)
    {
        hwnd_render_target_->Release();
        hwnd_render_target_ = nullptr;
    }
    if (!fonts_.empty())
    {
        for (auto font : fonts_)
        {
            font.second->Release();
        }
        fonts_.clear();
    }
    if (dwrite_text_layout_)
    {
        dwrite_text_layout_->Release();
        dwrite_text_layout_ = nullptr;
    }
    if (dwrite_factory_)
    {
        dwrite_factory_->Release();
        dwrite_factory_ = nullptr;
    }
}
bool graphics::init(const HWND hwnd)
{
    window_handle_ = hwnd;
    HRESULT result = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &factory_);
    if (!check_hr(result))
    {
        return false;
    }
    RECT rect;
    GetClientRect(window_handle_, &rect);
    result = factory_->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),
                                              D2D1::HwndRenderTargetProperties(
                                                  window_handle_,
                                                  D2D1::SizeU(rect.right - rect.left, rect.bottom - rect.top)),
                                              &hwnd_render_target_);
    if (!check_hr(result))
    {
        return false;
    }
    result = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(dwrite_factory_),
                                 reinterpret_cast<IUnknown **>(&dwrite_factory_));
    if (!check_hr(result))
    {
        return false;
    }

    result = dwrite_factory_->CreateTextFormat(L"Ubuntu", nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
                                               DWRITE_FONT_STRETCH_NORMAL, 14, L"", &dw_text_format_);
    if (!check_hr(result))
    {
        return false;
    }

    result = dw_text_format_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
    if (!check_hr(result))
    {
        return false;
    }
    result = dw_text_format_->SetParagraphAlignment(DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
    if (!check_hr(result))
    {
        return false;
    }
    result = hwnd_render_target_->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Gray), &black_brush_);
    if (!check_hr(result))
    {
        return false;
    }
    GetClientRect(window_handle_, &window_rect_);
    get_dpi_data();
    button_ = new gui::button_base(&hwnd_render_target_, &dwrite_factory_, L"Button Text", &dw_text_format_);
    button_->init(10, 10, 0, 0, {5,5,5,5});
    std::wstringstream string_stream;
    string_stream << L"Client size — Width: " << window_rect_.right - window_rect_.left << ", Height: " << window_rect_.
        bottom - window_rect_.top;
    copy_of_str_ = string_stream.str();
    resize();
    return true;
}
void graphics::begin_draw() const
{
    hwnd_render_target_->BeginDraw();
}
void graphics::end_draw() const
{
    hwnd_render_target_->EndDraw();
}
void graphics::render()
{
    begin_draw();
    hwnd_render_target_->Clear(D2D1::ColorF(D2D1::ColorF::WhiteSmoke));
    draw_text(L"ubuntu", copy_of_str_, (window_rect_.right - window_rect_.top) - metrycs_.width - 10, 10);
    draw_text(L"ubuntu", L"Text Clipped to left bottom. Test Unicode: 特にあなたのために。", 10,
              window_rect_.bottom - window_rect_.top - 25);
    button_->draw();
    end_draw();
}
IDWriteTextFormat* graphics::get_text_format(const std::wstring font_name)
{
    const std::map<std::wstring, IDWriteTextFormat*>::iterator it = std::find_if(
        fonts_.begin(), fonts_.end(), [&](const std::pair<const std::wstring, IDWriteTextFormat*>& p)
        {
            return p.first == font_name && p.second != nullptr;
        });
    if (it != fonts_.end())
    {
        return (*it).second;
    }
    return nullptr;
}
void graphics::draw_text(const std::wstring font_name, std::wstring text, const int x, const int y) const
{
    hwnd_render_target_->DrawTextW(text.c_str(), text.length(), dw_text_format_,
                                   D2D1::RectF(float(x), float(y), window_rect_.right, window_rect_.bottom), black_brush_,
                                   D2D1_DRAW_TEXT_OPTIONS_CLIP);
}
void graphics::resize()
{
    IDWriteTextLayout* layout;
    GetClientRect(window_handle_, &window_rect_);
    InvalidateRect(window_handle_, &window_rect_, false);
    HRESULT result = dwrite_factory_->CreateTextLayout(copy_of_str_.c_str(),
        copy_of_str_.length(),
        dw_text_format_,
        window_rect_.right - window_rect_.left,
        window_rect_.bottom - window_rect_.top, reinterpret_cast<IDWriteTextLayout**>(&layout));
    check_hr(result);
    result = hwnd_render_target_->Resize(D2D1::SizeU(window_rect_.right - window_rect_.left,
                                                     window_rect_.bottom - window_rect_.top));
    DWRITE_TEXT_METRICS met;
    layout->GetMetrics(&met);
    metrycs_ = met;
    if (FAILED(result))
    {
        _com_error err = result;
        MessageBoxW(window_handle_, err.ErrorMessage(), L"Error", MB_OK | MB_ICONERROR);
        return;
    }
    std::wstringstream string_stream;
    string_stream << L"Client size — Width: " << window_rect_.right - window_rect_.left << ", Height: " << window_rect_.
        bottom - window_rect_.top;
    copy_of_str_ = string_stream.str();
    render();
    layout->Release();
}
graphics::dpi_data graphics::get_dpi_data()
{
    dpi_data tmpp;
    memset(&tmpp, 0, sizeof(dpi_data));
    factory_->GetDesktopDpi(&tmpp.x, &tmpp.y);
    current_dpi_data_ = tmpp;
    return current_dpi_data_;
}
Answer 1

Ну, вот, например, возможность для утечки.

Вы создаёте layout через CreateTextLayout, затем переписываете result возвращаемым значением hwnd_render_target_->Resize. Если это возвращаемое значение не пройдёт проверку if (FAILED(result)), вы выходите из функции, не освободив layout.

READ ALSO
Аналог функции number_format в JS?

Аналог функции number_format в JS?

В PHP есть number_formatКакой аналог есть в JS/jQuery?

389
Как сделать фокус при наведении

Как сделать фокус при наведении

При наведении на ссылку из главного меню, загорается подсветка, но при отведения мыши от этой ссылки подсветка исчезаетКак сделать так что...

354
Как выбрать потомков от родителя в jQuery?

Как выбрать потомков от родителя в jQuery?

Подскажите, пожалуйста самый простой способ выбрать 3-х потомков от одинаковых родителейПриведу пример

361
Отцентрировать текст на изображении

Отцентрировать текст на изображении

ПриветНе могу понять как сделать так, чтобы поверх изображения отцентрировать текст относительно самого изображения, чтобы при ресайзе...

323