我有两个资源管理类DeviceContext
和OpenGLContext
,它们都是class DisplayOpenGL
的成员。资源生命周期与DisplayOpenGL
绑定。初始化看起来像这样(伪代码):
DeviceContext m_device = DeviceContext(hwnd);
m_device.SetPixelFormat();
OpenGLContext m_opengl = OpenGLContext(m_device);
字符串
问题在于对SetPixelFormat()的调用,因为我不能在DisplayOpenGL
c 'tor的初始化器列表中这样做:
class DisplayOpenGL {
public:
DisplayOpenGL(HWND hwnd)
: m_device(hwnd),
// <- Must call m_device.SetPixelFormat here ->
m_opengl(m_device) { };
private:
DeviceContext m_device;
OpenGLContext m_opengl;
};
型
我能看到的解决方案:
- 插入
m_dummy(m_device.SetPixelFormat())
-不会工作,因为SetPixelFormat()没有retval。(如果它有retval,你应该这样做吗?) - 使用
unique_ptr<OpenGLContext> m_opengl;
代替OpenGLContext m_opengl;
。
然后初始化为m_opengl()
,在c 'tor主体中调用SetPixelFormat()并使用m_opengl.reset(new OpenGLContext);
- 从
DeviceContext
控制器调用SetPixelFormat()
这些解决方案中哪一个更可取,为什么?我错过了什么吗?
我在Windows上使用Visual Studio 2010 Express,如果有关系的话。
**编辑:**我最感兴趣的是在决定这些方法之一时所涉及的权衡。
m_dummy()
不工作,即使它会工作,也看起来不优雅unique_ptr<X>
对我来说很有趣-什么时候我会用它来代替“普通”的X m_x
成员?除了初始化问题之外,这两个方法在功能上似乎或多或少是等效的。- 从
DeviceContext
c 'tor调用SetPixelFormat()
当然可以工作,但对我来说感觉不干净。DeviceContext
应该管理资源并启用其使用,而不是将一些随机像素格式策略强加给用户。 - stijn's
InitDev()
看起来是最干净的解决方案。
在这种情况下,我是否总是想要一个基于智能指针的解决方案?
9条答案
按热度按时间ih99xse11#
Comma operator to the rescue!表达式
(a, b)
将首先计算a
,然后计算b
。字符串
a6b3iqyw2#
在这种情况下,我是否总是想要一个基于智能指针的解决方案?
不。避免不必要的麻烦。
有两个尚未提及的直接方法:
方法A:
干净的方式。
为
m_device
的存储创建一个小容器对象,它在构造函数中调用SetPixelFormat()
。然后用该类型的示例替换DisplayOpenGL ::m_device
。初始化命令已获得,并且意图相当明确。插图:字符串
方法B:
快速和肮脏的方式。在这种情况下,可以使用静态函数:
型
eqqqjvef3#
首先你做错了:-)在构造函数中做复杂的事情是非常糟糕的实践。让这些操作在一个辅助对象上运行,而这个辅助对象必须传递给构造函数。更好的方法是在你的类之外构造你的复杂对象,并将它们完全创建,这样如果你需要将它们传递给其他类,你也可以同时将它们传递给它们的构造函数。另外,这样您就有机会检测错误,添加合理的日志记录等。
字符串
atmip9wb4#
如果
OpenGLContext
有一个0参数的构造函数和复制构造函数,可以将构造函数更改为字符串
unique_ptr
通常用于使其中一个成员为可选或“可空”的情况,在这里您可能希望这样做,也可能不希望这样做。balp4ylt5#
在这里使用uniqe_ptr似乎是合适的:你可以转发声明DeviceContext和OpenGLContext,而不是包括它们的头,也就是a good thing)。然后这个工作:
字符串
如果你可以使用c++11,你可以用lambda替换InitDev()。
wmvff8tz6#
如果它属于
DeviceContext
(从代码中看似乎是这样),则从DeviceContext
c'tor调用它。elcex8rz7#
将Comma operator与IIFE (Immediately-Invoked Function Expression)结合使用,它允许您定义变量和其他仅使用逗号运算符无法实现的复杂内容:
字符串
xpcnnkqh8#
逗号操作符在您的情况下会做得很好,但我认为这个问题是您的类计划不好的结果。我要做的是让构造函数只初始化对象的状态,而不初始化依赖项(比如OpenGL渲染上下文)。我假设OpenGLContext的构造函数初始化了OpenGL渲染上下文,这是我不会做的。相反,我会为OpenGLContext类创建
CreateRenderingContext
方法来进行初始化,并调用SetPixelFormat
字符串
tp5buhyn9#
逗号运算符是我首先想到的。构造函数链也可以让你稍微整理一下。
然而,我认为我已经提出了一种更整洁的方法,使您的意图清晰,并且在您的成员的真实的初始化周围产生较少的混乱-这在观察资源管理时很重要。
字符串
可作为gist here提供