在我的代码中,我在lambda中创建一个shared_ptr
,以便将PNG文件保存为后台任务。不幸的是,即使我有shared_ptr
的自定义删除器,似乎没有正确释放字节。
我用来创建shared_ptr
的代码:
std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), [](GLubyte* buffer) {
free(buffer);
});
为了保存文件并最终解除分配:
std::thread t([=, buffer = std::move(buffer)]() mutable {
bool done = writePNGFileFromBuffer(path, buffer.get(), width, height);
return done;
});
t.detach();
我试图将buffer.reset()
放在lambda中,但是虽然缓冲区为空,但内存不会被释放。我也尝试将创建者功能更改为:
std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), std::free);
但它也行不通。现在我一直在使用lambda删除器,因为我可以尝试在内部放置一个断点并检查free
是否被调用,但内存仍未释放。
此外,我已经验证,如果我将free(buffer.get())
放在lambda中,则该版本有效,但是对我来说这是没有意义的,因为我正在使用shared_ptr
以避免像此
你能帮我发布这个缓冲区吗?非常感谢你。
答案 0 :(得分:1)
我写了这个小测试工具来证明新的/删除是正确的。
注意在缓冲区构造函数中使用new / delete []。你使用malloc / free会给代码带来难闻的气味。求助于自由(ptr.get())隐藏了一些你尚未解决的逻辑问题。如果你把它留在程序中,它会在以后咬你。
proxy
作为GLubyte的替代品,计算分配和销毁的数量,因此我可以确认assert
每个构造都有相应的破坏。
#include <iostream>
#include <memory>
#include <thread>
#include <cassert>
#include <atomic>
using namespace std;
#define USE_PROXY 1
struct proxy
{
proxy() {
++_count;
}
~proxy() {
--_count;
}
static std::atomic<size_t> _count;
};
std::atomic<size_t> proxy::_count = { 0 };
#if USE_PROXY
using GLubyte = proxy;
#else
//using GLubyte = uint8_t;
#endif
bool writePNGFileFromBuffer(const char* path, const GLubyte* bytes, int width, int height)
{
return true;
}
auto main() -> int
{
{
int dataLength = 10000;
auto buffer = std::shared_ptr<GLubyte>(new GLubyte[dataLength],
[](GLubyte* p) { delete[] p; });
const char* path = "/tmp/foo";
int width = 100, height = 100;
std::thread t([=, buffer = std::move(buffer)]() mutable {
bool done = writePNGFileFromBuffer(path, buffer.get(), width, height);
return done;
});
t.join();
assert(!buffer);
}
assert(proxy::_count == 0);
return 0;
}
为了进一步考虑,您可能想知道如何处理write....
函数中的失败案例。目前,返回值正在被抛弃。我们有几种方法可以解决这个问题 - 一种方法是提供一个可以在写操作完成时调用的lambda。另一种方法是将写操作包装成std :: async。
bool writeSharedPNGFileFromBuffer(const char* path, shared_ptr<const GLubyte> bytes, int width, int height)
{
return writePNGFileFromBuffer(path, bytes.get(), width, height);
}
auto main() -> int
{
{
int dataLength = 100;
auto buffer = std::shared_ptr<GLubyte>(new GLubyte[10000], [](GLubyte* p) { delete[] p; });
const char* path = "/tmp/foo";
int width = 100, height = 100;
auto f = std::async(launch::async, writeSharedPNGFileFromBuffer, path, move(buffer), width, height);
// f is a std::future - a handle to somewhere the result will eventually land.
// perform main thread work here...
// ... and get the return value when we're ready to deal with it
auto written = f.get();
cout << "written: " << written << endl;
assert(!buffer);
}
assert(proxy::_count == 0);
return 0;
}