我正在嘗試使用 C 20 范圍和函式式編程將所有真字體加載到目錄中。但是,由于字體是一種資源,我在范圍介面內分配記憶體。我認為這就是為什么 valgrind 認為我有泄漏。我有一些std::views新分配的原始指標最終被丟棄 - 但是,這些原始指標被轉換并復制到唯一指標的向量中。
有問題的代碼:
// free a font resource
struct font_deleter {
void operator()(TTF_Font * font) { TTF_CloseFont(font); }
};
// aliases
using unique_font = std::unique_ptr<TTF_Font, font_deleter>;
using font_table = std::unordered_map<std::string, TTF_Font *>;
template<typename expected_t>
using result = tl::expected<expected_t, std::string>;
// determine if a path is a valid font file
auto _is_font_fxn(std::error_code & ec) {
return [&ec](fs::path const & path) {
return fs::is_regular_file(path, ec) and path.extension() == ".ttf";
};
}
// load a font-name, font-pointer pair from a font file
font_table::value_type _load_as_pair(fs::path const & path)
{
return std::make_pair(path.stem(), TTF_OpenFont(path.c_str(), 100));
}
// create a unique font pointer from a name-pointer pair
unique_font _ufont_from_pair(font_table::value_type const & pair)
{
return unique_font(pair.second, font_deleter{});
}
// determine if a font pointer is null from a name-pointer pair
bool _font_is_null(font_table::value_type const & pair)
{
return pair.second == nullptr;
}
result<std::vector<unique_font>>
button_factory::load_all_fonts(fs::path const & dir)
{
namespace views = std::views;
namespace ranges = std::ranges;
std::error_code ec; // using error codes tells filesystem not to throw
// make sure the path exists and is a valid directory
if (not fs::exists(dir, ec) or not fs::is_directory(dir, ec)) {
std::stringstream message;
if (ec) { message << ec.message(); } // an os call failed
else if (not fs::exists(dir)) { message << dir << " doesn't exist"; }
else if (not fs::is_directory(dir)) { message << dir << " isn't a directory"; }
return tl::unexpected(message.str());
}
// recursively get all paths in directory
std::vector<fs::path> paths(fs::recursive_directory_iterator(dir, ec), {});
// filter only font files and load them as name-font pairs
auto is_font = _is_font_fxn(ec);
auto fonts = paths | views::filter(is_font) | views::transform(&_load_as_pair);
// put all the successfully loaded fonts into a vector of unique pointers
// the font resources are freed automatically if returning unexpected
// otherwise this is the expected result
std::vector<unique_font> font_handle;
auto into_handles = std::back_inserter(font_handle);
ranges::transform(fonts, into_handles, &_ufont_from_pair);
// abort if any os calls failed in the process, or if some fonts didn't load
if (ec) { return tl::unexpected(ec.message()); }
if (ranges::any_of(fonts, &_font_is_null)) { return tl::unexpected(TTF_GetError()); }
// add all the loaded fonts definitions to the button factory
auto into_table = std::inserter(_fonts, _fonts.end());
ranges::copy(fonts, into_table);
return font_handle;
}
附帶說明一下,我正在使用TartanLLama 的建議實作,這std::expected是tl::命名空間的來源。
我從 valgrind 收到了一些粗糙的模板錯誤訊息,所以我將嘗試分享重要的部分。兩個塊中丟失了 62,000 個位元組,雖然模板錯誤是一場噩夢,但它似乎都來自范圍介面。似乎第一個塊中的訊息來自呼叫,ranges::any_of第二個來自ranges::copy- 兩個塊都提到_load_pair- 我猜是泄漏的記憶體的來源。
是否有某種原因我沒有看到為什么這可能會泄漏記憶體,或者這是一個 valgrind 錯誤?
uj5u.com熱心網友回復:
views::transform是惰性的 - 在訪問視圖的元素之前不會呼叫轉換函式。但這也意味著每次訪問視圖元素時都會呼叫轉換函式。
因此,每次您迭代時fonts-首先是transform,然后是any_of,最后是copy,您都在呼叫_load_as_pair,因此TTF_OpenFont再次呼叫-并泄漏結果。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/417711.html
標籤:
上一篇:如何正確增加這種“半鉆石”形狀?
下一篇:STL向量實作標頭大小
