Shared_ptr does not free user malloc on stream

In my code, I am creating shared_ptr

inside a lambda to save the PNG file as a background task. Unfortunately, even though I have a custom deleter for it shared_ptr

, it seems the bytes are not deallocated correctly.

The code I am using to create shared_ptr

:

std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), [](GLubyte* buffer) {
        free(buffer);
    });

      

And to save the file and finally free it:

std::thread t([=, buffer = std::move(buffer)]() mutable {
        bool done = writePNGFileFromBuffer(path, buffer.get(), width, height);
        return done;
    });
t.detach();

      

I tried to put buffer.reset()

inside a lambda but although the zero memory buffer is not freed. I also tried changing the creator function to something like:

std::shared_ptr<GLubyte> buffer = std::shared_ptr<GLubyte>((GLubyte*) malloc(*dataLength), std::free);

      

But it doesn't work either. Now I am using lambda deleter because then I can try to put a breakpoint inside and check the call free

, but the memory is still not released.

Also, I have confirmed that the release works if I put a free(buffer.get())

lambda inside, but it doesn't make sense to me because I use shared_ptr

to avoid things like this.

Can you help me free this buffer? Thank you very much.

+3


source to share


1 answer


I wrote this little test posting to prove that the new / delete was done correctly.

Note the use of new / delete [] in the buffer constructor. Your use of malloc / free gives the code a bad smell. Resorting to free (ptr.get ()) hides another boolean problem that you haven't solved. If you leave this in the program, he will bite you later.

proxy

acts as a replacement for GLubyte, which counts the allocated and destroyed, so I can confirm with help assert

that each construct has a corresponding destruction.



#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;
}

      

for further consideration, you may have wondered how you can handle a failure in a function write....

. The return value is currently being thrown. There are several ways we could deal with this: one is to supply a lambda that can be called when the write operation is complete. Another is to port the write operation to 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;
}

      

+1


source







All Articles