Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda capture shared_ptr member

I have a class OpenGLRenderer which has a class member mMemoryAllocator that is a std::shared_ptr<MemoryAllocator>. The reason I keep the memory allocator in a shared_ptr, is because even if the shared_ptr<Texture> returned below outlives it's creator theOpenGLRenderer, the MemoryAllocator instance will still be valid if I capture it by value, as it increments the ref count:

std::shared_ptr<Texture> OpenGLRenderer::CreateTexture(TextureType textureType, const std::vector<uint8_t>& textureData, uint32_t textureWidth, uint32_t textureHeight, TextureFormat textureFormat)
{
    return std::shared_ptr<Texture>(mMemoryAllocator->AllocateObject<Texture>(
                                    textureData, textureWidth, textureHeight,
                                    textureFormat, textureType, mLogger), 
                                    [=](Texture* texture) { 
                                        mMemoryAllocator
                                         ->DeallocateObject<Texture>(texture); 
                                    });
}

...But, it dosn't work. If OpenGLRenderer goes out of scope before the std::shared_ptr<Texture>, the std::shared_ptr<MemoryAllocator> becomes corrupted, and thus the lambda expression goes bonkers. What have I done wrong?

like image 506
KaiserJohaan Avatar asked Oct 22 '13 21:10

KaiserJohaan


1 Answers

The problem in this case is that lambdas don't capture members of the object, but the this pointer. A simple workaround is to create a local variable and bind that:

std::shared_ptr<Texture> 
OpenGLRenderer::CreateTexture(TextureType textureType, 
                              const std::vector<uint8_t>& textureData, 
                              uint32_t textureWidth, uint32_t textureHeight, 
                              TextureFormat textureFormat)

{
    std::shared_ptr<AllocatorType> allocator = mMemoryAllocator;
    return std::shared_ptr<Texture>(mMemoryAllocator->AllocateObject<Texture>(
                                    textureData, textureWidth, textureHeight,
                                    textureFormat, textureType, mLogger), 
                                    [=](Texture* texture) { 
                                        allocator
                                         ->DeallocateObject<Texture>(texture); 
                                    });
}
like image 66
David Rodríguez - dribeas Avatar answered Oct 20 '22 03:10

David Rodríguez - dribeas