多次调用初始化函数时的最佳做法?

时间:2010-11-18 13:53:13

标签: c++ error-handling initialization

这可能是一个主观问题,但我或多或少地要求它,并希望人们分享他们的经验。 (因为这是我在C ++中缺少的最重要的东西)

无论如何,假设我有一个不明确的理由 - 初始化函数从堆中初始化数据结构:

void initialize() {
    initialized = true;
    pointer = new T;
}

现在当我调用初始化函数两次时,会发生内存泄漏(对吗?)。所以我可以通过多种方式防止这种情况:

  • 忽略通话(只是检查我是否已初始化,如果我不做任何事情)
  • 发生错误
  • 自动“清理”代码,然后重新初始化。

现在通常的“最佳”方法是什么,这有助于将我的代码保留在未来?

编辑:谢谢您的回答。但是,我想知道人们如何处理这是一种更通用的方式。 - 人们如何处理可以被忽略的“简单”错误。 (比如,调用相同的函数两次,而只有一次是有意义的。)

6 个答案:

答案 0 :(得分:4)

你是唯一能够真正回答这个问题的人:你是否认为initialize函数最终可以被调用两次,或者这是否意味着你的程序出现意外情况执行流程?

  • 如果可以多次调用initialize函数:只需通过测试是否已经进行分配来忽略该调用。
  • 如果initialize函数没有合理的理由可以被多次调用:我相信这将是一个很好的候选例外。

为了清楚起见,我不相信清理并重新生成是一个可行的选择(或者你应该认真考虑重命名函数以反映这种行为)。

答案 1 :(得分:2)

对于可能并不总是需要的昂贵数据结构的按需延迟初始化,这种模式并不罕见。 Singleton是一个示例,或者是满足这些条件的类数据成员。

如果结构已经到位,我会做的就是跳过初始化代码。

void initialize() {
    if (!initialized)
    {
      initialized = true;
      pointer = new T;
    }
}

如果你的程序有多个线程,你必须包含锁定才能使这个线程安全。

答案 2 :(得分:0)

我会考虑使用boost或STL智能指针。

答案 3 :(得分:0)

我认为答案完全取决于T(以及本课程的其他成员)。如果它们是轻量级的并且没有重新创建新副本的副作用,那么一定要清理并重新创建(但使用智能指针)。另一方面,如果它们很重(比如网络连接或类似的东西),如果设置了布尔值,你应该绕过它...

您还应该调查boost::optional,这样您就不需要整体标记,并且对于应该存在的每个对象,您可以检查是否实例化然后根据需要进行实例化...(比如说第一遍,有些构造没问题,但有些失败..)

答案 4 :(得分:0)

在构造函数之后设置数据成员的想法很常见,所以不要担心你肯定不是第一个遇到这个问题的人。

有两种典型的用例:

  • 按需/懒惰实例化:如果你不确定它会被使用并且创建成本很高,那么最好不要在构造函数中初始化它
  • 缓存数据:缓存潜在昂贵操作的结果,以便后续调用无需再次计算

您处于“懒惰”类别,在这种情况下,更简单的方法是使用标志或可空值:

  • flag + value组合:在没有堆分配的情况下重用现有类,但这需要默认构造
  • 智能指针:这会绕过默认的构造问题,代价是堆分配。检查你需要的复制语义......
  • boost::optional<T>:类似于指针,但具有深层复制语义且没有堆分配。要求类型完全定义,依赖性更重。

我强烈推荐boost::optional<T>成语,或者如果您希望提供依赖性绝缘,您可能会回到智能指针,如std::unique_ptr<T>(或boost::scoped_ptr<T>如果您没有访问权限到C ++ 0x编译器。)

答案 5 :(得分:-1)

我认为这可能是可以应用Singleton模式的情况。