std::shared_ptr 删除器类型
std::shared_ptr Deletor Type
我在尝试将自定义删除器传递给 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*
-> 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
我很困。
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
有一种更简洁的方法来做你想做的事,使用共享指针的一个非常棒且文档不足的特性:
// 1
std::shared_ptr<SDL_Surface> surface_ptr {
SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGB888, 0),
[](SDL_Surface* p) {
if(SDL_MUSTLOCK(p))
SDL_UnlockSurface(p);
SDL_FreeSurface(p);
}
};
// 2
std::shared_ptr<unsigned char> pixels = { surface_ptr, surface->pixels };
第 1 行分配表面并将其置于具有自定义删除器的共享指针的控制之下。
第 2 行是很棒的部分。它初始化一个共享指针指向像素数据,同时使用与表面相同的控制块。
这意味着只有当两个共享指针都被销毁或重置时,表面才会被删除。它是保存引用计数和删除器的控制块,因此您不必担心两个共享指针指向不同的类型——第二个只是第一个的方便外观。
请注意,您不必在 lambda 中捕获任何内容 - shared_ptr 会为您完成此操作并将表面地址作为参数传递。
我在尝试将自定义删除器传递给 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*
-> 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 我很困。
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
有一种更简洁的方法来做你想做的事,使用共享指针的一个非常棒且文档不足的特性:
// 1
std::shared_ptr<SDL_Surface> surface_ptr {
SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_RGB888, 0),
[](SDL_Surface* p) {
if(SDL_MUSTLOCK(p))
SDL_UnlockSurface(p);
SDL_FreeSurface(p);
}
};
// 2
std::shared_ptr<unsigned char> pixels = { surface_ptr, surface->pixels };
第 1 行分配表面并将其置于具有自定义删除器的共享指针的控制之下。
第 2 行是很棒的部分。它初始化一个共享指针指向像素数据,同时使用与表面相同的控制块。
这意味着只有当两个共享指针都被销毁或重置时,表面才会被删除。它是保存引用计数和删除器的控制块,因此您不必担心两个共享指针指向不同的类型——第二个只是第一个的方便外观。
请注意,您不必在 lambda 中捕获任何内容 - shared_ptr 会为您完成此操作并将表面地址作为参数传递。