Jos*_*son 1 c++ valgrind sdl-ttf sdl-2 std-ranges
我正在尝试使用 C++20 范围和函数式编程加载目录中的所有 true-type 字体。但是,由于字体是一种资源,因此我在范围接口内分配内存。我想这就是 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;
}
Run Code Online (Sandbox Code Playgroud)
附带说明一下,我正在使用TartanLLama 的提议实现,这就是命名空间的std::expectedtl::来源。
我从 valgrind 收到一些粗糙的模板错误消息,因此我将尝试分享重要的部分。两个块中丢失了 62,000 个字节,虽然模板错误是一场噩梦,但它似乎全部来自范围接口。似乎第一个块中的消息来自调用ranges::any_of,第二个块来自ranges::copy调用 - 两个块都提到_load_pair- 我猜测是内存泄漏的来源。
是否有某种原因我没有明白为什么这可能会泄漏内存,或者这是一个 valgrind 错误?
views::transform是惰性的- 在访问视图的元素之前不会调用转换函数。但这也意味着每次访问视图元素时都会调用转换函数。
因此,每次您迭代fonts- 首先是transform,然后是any_of,最后是copy,您都会调用_load_as_pair,因此会TTF_OpenFont再次调用 - 并泄漏结果。
| 归档时间: |
|
| 查看次数: |
103 次 |
| 最近记录: |