gpt4 book ai didi

c++ - 在 C++ 构造器中管理 bad_alloc 异常

转载 作者:太空狗 更新时间:2023-10-29 23:34:36 24 4
gpt4 key购买 nike

我有 Java 经验,最近正在编写一些 C++ 代码。我的问题是,如果我有 A 类,我必须在其中实例化 B 类和 C 类作为 A 的两个成员变量。

如果在 A 的构造函数中,我是否应该假设类 B 和 C 的分配永远不会失败,并在 A 的析构函数中处理错误分配异常?

如果我不做那个假设,意思是我添加一些try catch block 来捕获类B和类C的bad_alloc,那么如果发生分配异常,我是否应该在A的构造函数中进行清理?

推荐的做法是什么?如果“new”产生了错误的分配,指针携带什么值?

最佳答案

如果在构造 A 期间抛出异常,您的析构函数将不会被调用。

显然,解决方案取决于您在做什么,但理想情况下,您不必做任何清理工作。你应该利用 RAII ,你的类(class)成员应该清理自己。

也就是说,不要使用任何原始指针;把它们包起来,让 wrapper 来处理。惊喜! C++ 程序员和你一样讨厌内存管理。我们喜欢把它包起来然后忘记它。

不过,如果您真的需要,我认为这很常见:

struct foo
{
int* i;
some_member_that_could_throw crap;

foo() // do *not* new i! if the second member throws, memory is leaked.
{ // rather:

// okay we made it, the other member must have initialized
i = new int;
}
};

关于您的指针,它的值保持不变。当 new 抛出异常(无论出于何种原因)时,堆栈将展开。表达式的其余部分被放弃。


以下是异常和对象创建的工作原理。这是一个递归过程,因为每个成员或基类将依次遵循此列表。基本类型没有构造函数;这是递归的基本情况。

  1. 首先,构造我们的每个基类。 (依次运行此列表。)
  2. 逐一初始化类(class)成员。
  3. 运行构造函数主体。
  4. 以一个完整构造的对象结束。

显然,如果第 1 项失败,我们就没有任何清理工作要做,因为我们的成员都没有被初始化。我们在那里很好。

两者不同。如果其中任何一个构造函数失败,初始化的成员到目前为止将被破坏,然后构造函数将停止进程并且异常继续它的快乐方式。这就是为什么当您让您的成员自行清理时,您无需担心。未初始化的无事可做,已初始化的将运行其析构函数,在此处进行清理。

三个更是如此。现在您的对象已完全初始化,您可以保证它们都将运行其析构函数。再一次,把事情包起来,你就没有什么可担心的了。 但是如果你周围有一个原始指针,这就是 try/catch block 的时候了:

try
{
// some code
}
catch (..) // catch whatever
{
delete myrawPointer; // stop the leak!
throw; // and let the exception continue
}

在没有 RAII 的情况下编写异常安全代码会更加困惑。

关于c++ - 在 C++ 构造器中管理 bad_alloc 异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2505257/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com