std::shared_ptr::reset() "invalidates" 其他参考文献
std::shared_ptr::reset() "invalidates" other references
此时我所有的代码都是单线程的。
我有一个纹理管理器,它拥有 "texture collections" 的集合,这些集合又包含 "own" 并将我所有游戏的纹理管理为 std::shared_ptr's
。一个集合专门用于我的帧缓冲区纹理。在初始化时,它实例化了我所有的帧缓冲区纹理,稍后,一个单独的帧缓冲区对象请求它们并存储它自己的 std::shared_ptr
对这些纹理的引用。我在我的延迟渲染器中使用这个对象。到目前为止没有问题:查看 Visual Studio (2015) 中的调试信息,它显示每个帧缓冲区纹理有两个强引用(一个在集合中,一个在帧缓冲区对象中);正常工作。
当我的 window 尺寸发生变化时,问题就出现了。我监听 WM_SIZE
事件,在调整大小时,我的 WndProc 调用以下命令(同样,在我的帧缓冲区纹理集合中的引用,而不是我的帧缓冲区对象——遵守我的所有权约定):
void PantheraTextureCollectionFramebuffer::Resize( unsigned int width, unsigned int height ) {
_textures["depth"].reset( new PantheraTexture( width, height, PantheraTextureFormat::Depth24,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["diffuseSpecular"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["normalParallax"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["position"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["uvMaterial"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
}
它使用新的 window 尺寸重新创建所有纹理。 但是,帧缓冲区对象中的std::shared_ptr's
保持不变(除了每个纹理的引用计数,它下降到一个)。看来我从根本上误判了 std::shared_ptr
及其 reset()
方法。
我也试过使用间接重新分配,例如:
*_textures["depth"] = PantheraTexture(...)
除了感觉不愉快之外,它不会调用我的纹理对象的析构函数,因此 OpenGL 永远不会释放无效的纹理。
我很难过。我想让纹理对象本身保持不变,否则我可能会利用 glTexImage*D 为它们实现一个内部调整大小方法。您如何建议在不诉诸于此的情况下保持我的纹理集合和我的帧缓冲区对象之间的连续性?
提前致谢。
一般来说,解决这个问题的方法是停止使用 shared_ptr
来处理那些并不真正 object 的东西。
例如,您有一个 PantheraTextureCollectionFramebuffer
,我假设它代表帧缓冲区使用的 collection 纹理。这 object 拥有 那些纹理;它管理它们何时被创建、重新创建和销毁。
在其他地方,您可能有一些 Framebuffer
class。现在,它使用的纹理有 shared_ptr
s,代表对这些纹理的所有权。但它真的拥有那些纹理吗?
不是真的。现在是的,如果您在它们之间共享所有权,那么您可以在仍然使用帧缓冲区的同时销毁 collection。但是……你真的想要吗?
没有。从逻辑上讲,如果您销毁了 collection,那么使用 collection 的帧缓冲区应该 也 已被销毁,对吗?但与此同时,也许一个帧缓冲区可以使用来自多个 collections.
的纹理
在那种情况下,我会说帧缓冲区应该对它从中获取一个或多个图像的任何 collection 拥有所有权。
此外,这些 collection 似乎是一组命名图像。因此,用户可能会按名称引用纹理,根据需要从他们的 collection(s) 中获取实际纹理 object。
因此,collections 需要知道谁拥有它们,以便在更新或修改纹理时,可以通知他们。至少,这个帧缓冲区 collection class 需要在更新纹理时告知任何引用它的帧缓冲区,以便它们可以重新初始化所需的任何数据。
which, aside from feeling unpleasantly hacky, doesn't call my texture objects' destructors and so OpenGL never frees the invalid textures.
那你肯定没有在你的字体中正确使用Three/Five的规则。您允许它可复制,但您没有正确实现复制行为。
您应该制作您的类型 non-copyable,因为为纹理包装器实施正确的复制行为不是一个好主意。
此时我所有的代码都是单线程的。
我有一个纹理管理器,它拥有 "texture collections" 的集合,这些集合又包含 "own" 并将我所有游戏的纹理管理为 std::shared_ptr's
。一个集合专门用于我的帧缓冲区纹理。在初始化时,它实例化了我所有的帧缓冲区纹理,稍后,一个单独的帧缓冲区对象请求它们并存储它自己的 std::shared_ptr
对这些纹理的引用。我在我的延迟渲染器中使用这个对象。到目前为止没有问题:查看 Visual Studio (2015) 中的调试信息,它显示每个帧缓冲区纹理有两个强引用(一个在集合中,一个在帧缓冲区对象中);正常工作。
当我的 window 尺寸发生变化时,问题就出现了。我监听 WM_SIZE
事件,在调整大小时,我的 WndProc 调用以下命令(同样,在我的帧缓冲区纹理集合中的引用,而不是我的帧缓冲区对象——遵守我的所有权约定):
void PantheraTextureCollectionFramebuffer::Resize( unsigned int width, unsigned int height ) {
_textures["depth"].reset( new PantheraTexture( width, height, PantheraTextureFormat::Depth24,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["diffuseSpecular"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["normalParallax"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGBA8,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["position"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
_textures["uvMaterial"].reset( new PantheraTexture( width, height, PantheraTextureFormat::RGB16F,
PantheraTextureMinFilter::Nearest, PantheraTextureMagFilter::Nearest ) );
}
它使用新的 window 尺寸重新创建所有纹理。 但是,帧缓冲区对象中的std::shared_ptr's
保持不变(除了每个纹理的引用计数,它下降到一个)。看来我从根本上误判了 std::shared_ptr
及其 reset()
方法。
我也试过使用间接重新分配,例如:
*_textures["depth"] = PantheraTexture(...)
除了感觉不愉快之外,它不会调用我的纹理对象的析构函数,因此 OpenGL 永远不会释放无效的纹理。
我很难过。我想让纹理对象本身保持不变,否则我可能会利用 glTexImage*D 为它们实现一个内部调整大小方法。您如何建议在不诉诸于此的情况下保持我的纹理集合和我的帧缓冲区对象之间的连续性?
提前致谢。
一般来说,解决这个问题的方法是停止使用 shared_ptr
来处理那些并不真正 object 的东西。
例如,您有一个 PantheraTextureCollectionFramebuffer
,我假设它代表帧缓冲区使用的 collection 纹理。这 object 拥有 那些纹理;它管理它们何时被创建、重新创建和销毁。
在其他地方,您可能有一些 Framebuffer
class。现在,它使用的纹理有 shared_ptr
s,代表对这些纹理的所有权。但它真的拥有那些纹理吗?
不是真的。现在是的,如果您在它们之间共享所有权,那么您可以在仍然使用帧缓冲区的同时销毁 collection。但是……你真的想要吗?
没有。从逻辑上讲,如果您销毁了 collection,那么使用 collection 的帧缓冲区应该 也 已被销毁,对吗?但与此同时,也许一个帧缓冲区可以使用来自多个 collections.
的纹理在那种情况下,我会说帧缓冲区应该对它从中获取一个或多个图像的任何 collection 拥有所有权。
此外,这些 collection 似乎是一组命名图像。因此,用户可能会按名称引用纹理,根据需要从他们的 collection(s) 中获取实际纹理 object。
因此,collections 需要知道谁拥有它们,以便在更新或修改纹理时,可以通知他们。至少,这个帧缓冲区 collection class 需要在更新纹理时告知任何引用它的帧缓冲区,以便它们可以重新初始化所需的任何数据。
which, aside from feeling unpleasantly hacky, doesn't call my texture objects' destructors and so OpenGL never frees the invalid textures.
那你肯定没有在你的字体中正确使用Three/Five的规则。您允许它可复制,但您没有正确实现复制行为。
您应该制作您的类型 non-copyable,因为为纹理包装器实施正确的复制行为不是一个好主意。