首页 > 解决方案 > 避免在构造函数中分配或保持简单性(和 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 然后删除更简洁的方式为我删除了一些东西。

我被赋予“从不在构造函数中分配”的原因是,如果构造函数失败,则无法恢复该内存。但是同意下面的评论,我一直怀疑如果发生这种情况,我无论如何都会终止......

标签: c++constructorraii

解决方案


一个好的经验法则是每个类都应该有一个责任。std::vector我们已经有一些(模板)类负责处理堆分配的内存,例如std::stringstd::unique_ptr。大多数时候,您应该使用它们来避免给您的班级额外的内存处理责任。

现在,您可能需要一种标准类不提供的特定类型的内存处理。或者更常见的是,您还有一些其他非内存资源也需要清理处理 - 例如临时文件。在这种情况下,“一类,一项责任”的原则仍然有效。您将每个此类资源包装在其自己的资源管理类中。需要三个资源的更复杂的对象只有三个成员,每个成员处理一个资源。

C++ 现在确保即使存在异常,资源也不会丢失。即使在某个复杂对象的构造函数中间无法创建一个成员,C++ 也会安排销毁到目前为止创建的所有成员,并且只销毁那些成员。这为您提供了一种全有或全无的方法。没有半成品的对象。

要特别清楚:这仅适用构造函数。它不适用于您自己的setup(). 换句话说,C++ 有特定的规则来使资源获取在构造函数内部工作,而且只有. 这就是术语“资源获取即初始化”或 RAII 的原因。如果您的讲师建议不要在构造函数中分配资源,那么他们根本不了解 C++ 。


推荐阅读