如何像普通指针一样对唯一指针进行索引与写入?附代码示例
用std::unique_ptr替代原始指针操作OpenGL映射缓冲区
我来帮你搞定这个问题——要让std::unique_ptr像普通指针那样支持索引和写入,同时适配OpenGL映射缓冲区的特殊内存管理,核心是自定义删除器,因为这块内存不是用new分配的,不能让unique_ptr默认调用delete。下面是具体的实现步骤和代码示例:
1. 定义带自定义删除器的unique_ptr类型
首先我们封装一个适合的unique_ptr类型,复用起来更方便:
#include <memory> // 你的sphere结构体定义 struct alignas(16) sphere { glm::vec4 center; glm::vec4 color; float radius; }; // 定义带自定义删除器的unique_ptr,删除器负责解除OpenGL缓冲区映射 using UniqueSpherePtr = std::unique_ptr<sphere, void(*)(sphere*)>;
2. 创建自定义删除器
我们需要让unique_ptr在生命周期结束时自动调用glUnmapNamedBuffer释放映射内存,而非默认的delete。用lambda实现这个删除器:
// 捕获缓冲区对象m_sphere_buffer,确保删除器能正确解除对应缓冲区的映射 auto sphere_deleter = [m_sphere_buffer](sphere* ptr) { if (ptr != nullptr) { glUnmapNamedBuffer(m_sphere_buffer); } };
3. 用unique_ptr接管映射的内存
替换你原来的原始指针赋值逻辑,用UniqueSpherePtr接管glMapNamedBufferRange返回的指针:
// 替换原来的sphere* m_sphere_ptr; UniqueSpherePtr m_sphere_ptr( static_cast<sphere*>(glMapNamedBufferRange( m_sphere_buffer, 0, m_spheres.size() * sizeof(sphere), GL_MAP_WRITE_BIT )), sphere_deleter );
4. 索引和写入操作和普通指针完全一致
std::unique_ptr已经重载了operator[],所以你原来的循环代码不需要任何修改,直接像普通指针一样使用即可:
auto sphere_x_offset { 5.0f }; for (int index{ 0 }; index < m_spheres.size(); ++index) { float sphere_x { static_cast<float>(index) / m_spheres.size()}; // 直接用[]索引,和原始指针用法完全一样 m_sphere_ptr[index].center = glm::vec4{ sphere_x + sphere_x_offset, 0.0f, 0.0f, 1.0f }; // 其他字段的写入也同理 m_sphere_ptr[index].color = glm::vec4{ 1.0f, 0.5f, 0.2f, 1.0f }; m_sphere_ptr[index].radius = 1.0f; }
关键注意事项
- 检查映射是否成功:
glMapNamedBufferRange可能返回nullptr,建议增加错误检查:if (!m_sphere_ptr) { GLenum err = glGetError(); // 这里添加错误处理逻辑,比如打印错误信息 } - 不要手动调用glUnmapNamedBuffer:
unique_ptr会在自身销毁时自动调用删除器完成解除映射,手动调用会导致重复操作,引发OpenGL错误。 - 确保捕获的缓冲区有效:如果用lambda作为删除器,要保证
m_sphere_buffer在unique_ptr的整个生命周期内都是有效的(比如缓冲区对象没有被提前销毁)。
内容的提问来源于stack exchange,提问作者Startec
相关产品推荐
相关产品推荐

