实现指向非指针类型的unique_ptr编译报错求助
解决非指针类型std::unique_ptr的编译错误
咱们先来拆解你遇到的问题:你想把std::unique_ptr用来管理OpenGL的GLuint类型资源(不是指针),自定义了ShaderDeleter并把pointertypedef成GLuint,结果触发了编译错误——说unsigned int和std::nullptr_t没法用!=比较。
错误原因
std::unique_ptr本质是为指针类型设计的,它要求关联的pointer类型必须满足NullablePointer规则:简单说就是这个类型得能和nullptr做比较、能被赋值为nullptr,以此表示“空资源”状态。但GLuint本质是无符号整数,根本不支持和nullptr的比较操作,这就是编译器报错的核心原因。
解决方案1:自定义包装类(推荐)
我们可以给GLuint套一个简单的包装类,用OpenGL规定的无效ID(0)来表示“空”,同时实现和nullptr的比较逻辑,让它满足NullablePointer要求:
#include <memory> #include <GL/gl.h> // 包装GLuint,使其支持空值判断 struct GLuintWrapper { GLuint value = 0; // 用0表示空资源(OpenGL对象ID永远不会是0) // 实现和nullptr的比较 constexpr bool operator==(std::nullptr_t) const noexcept { return value == 0; } constexpr bool operator!=(std::nullptr_t) const noexcept { return !(*this == nullptr); } // 隐式转换回GLuint,方便直接调用OpenGL API operator GLuint() const noexcept { return value; } }; struct ShaderDeleter { // 将pointer类型改为我们的包装类 using pointer = GLuintWrapper; void operator()(GLuint shader) const { if (shader != 0) { // 只删除有效的Shader资源 glDeleteShader(shader); } } }; int main() { // 创建一个Vertex Shader GLuint shader_id = glCreateShader(GL_VERTEX_SHADER); // 直接用shader_id初始化unique_ptr,会自动隐式转换为GLuintWrapper std::unique_ptr<GLuint, ShaderDeleter> shader_ptr(shader_id); // 使用时可以直接把shader_ptr当作GLuint用 const char* source = "#version 330 core\n..."; glShaderSource(shader_ptr, 1, &source, nullptr); // ...后续编译、链接等操作 // 离开main函数作用域时,unique_ptr会自动调用ShaderDeleter释放资源 return 0; }
这个方案的好处是完全保留unique_ptr的语法糖,比如你可以直接用if (shader_ptr)判断资源是否有效,和普通指针类型的unique_ptr用法完全一致。
解决方案2:简化版(规避nullptr比较)
如果你不想写包装类,也可以利用OpenGL对象ID的特性(0是无效ID),直接用GLuint作为pointer类型,但要注意规避和nullptr的比较:
#include <memory> #include <GL/gl.h> struct ShaderDeleter { using pointer = GLuint; void operator()(GLuint shader) const { if (shader != 0) { glDeleteShader(shader); } } }; int main() { GLuint shader_id = glCreateShader(GL_VERTEX_SHADER); // 用0初始化空的unique_ptr,不要用nullptr std::unique_ptr<GLuint, ShaderDeleter> shader_ptr(0); // 赋值有效的Shader ID shader_ptr.reset(shader_id); // 不要用if (shader_ptr),而是手动调用get()检查值是否为0 if (shader_ptr.get() != 0) { const char* source = "#version 330 core\n..."; glShaderSource(shader_ptr.get(), 1, &source, nullptr); } return 0; }
这种方法的缺点是失去了unique_ptr原本的空值判断语法糖,每次检查资源都要手动调用get(),不够优雅,所以更推荐第一种方案。
内容的提问来源于stack exchange,提问作者Michael Mahn
相关产品推荐
相关产品推荐

