std :: shared_ptr Deletor Type

时间:2015-10-06 15:54:36

标签: c++ c++11 lambda shared-ptr

我在尝试将自定义deletor传递给std :: shared_ptr时遇到了奇怪的错误:

std::shared_ptr<unsigned char*> SDLWindow::drawGrid(const Grid* grid) { 
    SDL_Surface* rgbSurface = SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGB888, 0);
    //...error checking and locking the SDL_Surface, omitted for brevity
    unsigned char* pixelsPtr = (unsigned char*)(rgbSurface->pixels);

    //need a custom deleter because we created a copy of the SDL_Surface
    //we cant directly delete the pixel data but need to delete the underlying SDL_Surface instead
    auto surfaceDeleter = [rgbSurface](decltype(pixelsPtr)* ignored) 
            //don't directly delete the pixel buffer, delete the underlying SDL_Surface instead
            {
                //unlock the surface if necessary
                if(SDL_MUSTLOCK(rgbSurface))
                {
                    SDL_UnlockSurface(rgbSurface);
                }
                SDL_FreeSurface(rgbSurface);
            };
    return std::shared_ptr<unsigned char*>(pixelsPtr, surfaceDeleter);
}

(我改变了const unsigned char* - &gt; unsigned char*,如果与它有任何关系,但我希望尽可能使用const)

Clang说不能转换为nullptr_t,我认为这与shared_ptrs如何使用类型擦除有关(但为什么他们不能处理指针?)

    unsigned char* pixelsPtr = (unsigned char*)(rgbSurface->pixels);
[..]/src/SDLWindow.cpp:132:12: error: no matching constructor for initialization of 'std::shared_ptr<unsigned char *>'
    return std::shared_ptr<unsigned char*>(pixelsPtr, surfaceDeleter);
           ^                               ~~~~~~~~~~~~~~~~~~~~~~~~~
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/memory:3809:26: note: candidate constructor [with _Dp = (lambda at
      /[..]/src/SDLWindow.cpp:122:27)] not viable: no known conversion from 'unsigned char *' to 'nullptr_t' for 1st argument
    template <class _Dp> shared_ptr(nullptr_t __p, _Dp __d);

奇怪的是,g ++似乎给出了一个完全不同的错误:

                 from /[..]/src/SDLWindow.hpp:4,
                 from /[..]/src/SDLWindow.cpp:1:
/opt/local/include/gcc49/c++/bits/shared_ptr_base.h: In instantiation of 'std::__shared_ptr<_Tp, _Lp>::__shared_ptr(_Tp1*, _Deleter) [with _Tp1 = unsigned char; _Deleter = jakway_antf::SDLWindow::drawGrid(const jakway_antf::Grid*)::<lambda(unsigned char**)>; _Tp = unsigned char*; __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]':
/opt/local/include/gcc49/c++/bits/shared_ptr.h:130:37:   required from 'std::shared_ptr<_Tp>::shared_ptr(_Tp1*, _Deleter) [with _Tp1 = unsigned char; _Deleter = jakway_antf::SDLWindow::drawGrid(const jakway_antf::Grid*)::<lambda(unsigned char**)>; _Tp = unsigned char*]'
/[..]/src/SDLWindow.cpp:132:69:   required from here
/opt/local/include/gcc49/c++/bits/shared_ptr_base.h:881:37: error: cannot convert 'unsigned char*' to 'unsigned char**' in initialization
  : _M_ptr(__p), _M_refcount(__p, ntf::SDLWindow::drawGrid(const jakway_antf::))

关于g ++,我不知道发生了什么,因为我已经搞乱了lambda的参数并声明unsigned char**没有做任何事情。

我试过了:

  • 弄乱捕捉参数,这似乎没有做任何事情(从我几个小时前记得的事情)
  • 每一个方向投射
  • 使用std :: function而不是auto声明lambda 我很困惑。

2 个答案:

答案 0 :(得分:5)

使用共享指针的一个非常棒且记录不足的功能,有一种更清洁的方式来做你想要的事情:

define_singleton_method

第1行分配表面并将其置于具有自定义删除器的共享指针的控制之下。

第2行是很棒的部分。它使用相同的控制块作为表面,初始化一个指向像素数据的共享指针。

这意味着只有在两个共享指针都被销毁或重置时才会删除曲面。它是控制块,它保存引用计数和删除器,因此您不必担心两个共享指针指向不同的类型 - 第二个只是第一个方便的外观。

请注意,您不必捕获lambda中的任何内容 - shared_ptr会为您执行此操作并将表面地址作为参数传递。

答案 1 :(得分:3)

std::shared_ptr<unsigned char*>应为std::shared_ptr<unsigned char>。使用std::shared_ptr<unsigned char*>表示基础指针为unsigned char**shared_ptr<T>存储T*。由于您有unsigned char*我们希望T成为unsigned char