c++ - 避免在构造函数中分配或保持简单性(和 RAII?)
问题描述
大约 8 个月以来,我一直将游戏引擎作为一个项目来了解更多关于 c++ 的信息。我已经到了一个阶段,为了避免在构造函数中进行分配(根据大学讲师的建议),我对所有对象都有虚拟 setup() 方法,并使用 bool 来标记 setup 方法是否已被调用。但是,我遇到了各种逻辑错误,由于在设置中进行了分配,因此无法在构造函数中执行任何操作是一个巨大的痛苦。我也一直在阅读有关 RAII 的信息,似乎在构造函数中进行分配可能会更好,这样我就不必调用 setup 方法。
在构造函数中通过 new 分配内存有多糟糕?为了符合 RAII,我应该这样做吗?
编辑-只是为了澄清,人们指出使用 std::vector 容器等。我说的是为更多对象分配内存,而不是为数组和事物分配内存。例如 - 按钮对象需要为自己创建一个 TransformComponent 、一个 AnimationComponent 和一个 RenderComponent。目前,在 setup() 中,我将使用 new 创建它们。使用智能指针等是否意味着我不需要 new 关键字?
我正在创建的对象被转发到一个名为 addComponent(Component * ) 的基类方法,该方法将此组件存储在 Component * s 的 std::vector 中,因此我不能在结束时清理这些对象方法/构造函数。
我的印象是
ButtonClass()
{
SomeComponent * sc = new SomeComponent ();
addComponent(sc);
}
工作得很好,但是
ButtonClass()
{
SomeComponent sc = SomeComponent ();
addComponent(&sc);
}
将导致 sc 被清理,并且传递给 addComponent 的对它的引用将是指向空内存的指针。
如果使用智能指针否定了这一点,那么我误解了他们,我认为他们只是以一种比调用 new 然后删除更简洁的方式为我删除了一些东西。
我被赋予“从不在构造函数中分配”的原因是,如果构造函数失败,则无法恢复该内存。但是同意下面的评论,我一直怀疑如果发生这种情况,我无论如何都会终止......
解决方案
一个好的经验法则是每个类都应该有一个责任。std::vector
我们已经有一些(模板)类负责处理堆分配的内存,例如std::string
和std::unique_ptr
。大多数时候,您应该使用它们来避免给您的班级额外的内存处理责任。
现在,您可能需要一种标准类不提供的特定类型的内存处理。或者更常见的是,您还有一些其他非内存资源也需要清理处理 - 例如临时文件。在这种情况下,“一类,一项责任”的原则仍然有效。您将每个此类资源包装在其自己的资源管理类中。需要三个资源的更复杂的对象只有三个成员,每个成员处理一个资源。
C++ 现在确保即使存在异常,资源也不会丢失。即使在某个复杂对象的构造函数中间无法创建一个成员,C++ 也会安排销毁到目前为止创建的所有成员,并且只销毁那些成员。这为您提供了一种全有或全无的方法。没有半成品的对象。
要特别清楚:这仅适用于构造函数。它不适用于您自己的setup()
. 换句话说,C++ 有特定的规则来使资源获取在构造函数内部工作,而且只有. 这就是术语“资源获取即初始化”或 RAII 的原因。如果您的讲师建议不要在构造函数中分配资源,那么他们根本不了解 C++ 。
推荐阅读
- wpf - 为什么不显示数据网格?
- c - 如何修复运行时错误:加载 'const char 类型的空指针
- azure - 在进行增量 ARM 模板配置时保留 Web App 二进制文件
- r - 如何根据多选转换条形图的数据?
- autodesk-forge - 如何通过 bim360 api 或 sdk 下载计划 pdf 文件?
- arrays - 将 JSON 数组对象转换为 .net 类
- php - 如何修复“致命错误:第 168 行 public_html/vqmod/vqmod.php 中允许的内存大小为 268435456 字节已用尽(尝试分配 109 字节)”?
- c++ - 从图像中获取矩形轮廓
- python - 如何在python字典中的键和值之间切换(不改变它在内存中的位置)
- react-native - 如何通过 react-native-maps 创建一个标记?