【问题标题】:How do you prevent leaks when raising an exception in init?在 init 中引发异常时如何防止泄漏?
【发布时间】:2011-06-27 17:04:13
【问题描述】:

情况是这样的。假设我有一个名为 MYFoo 的类。这是它的初始化程序:

-init
{
  self = [super init];
  if (self)
  {
    // during initialization, something goes wrong and an exception is raised
    [NSException raise ...];
  }
  return self;
}

现在我想在其他地方使用 MYFoo 对象,所以我使用了一个通用模式:

MYFoo *foo = [[[MYFoo alloc] init] autorelease];

但是将会发生的是,即使在第二部分有一个 try/catch,一个 MYFoo 对象也将被分配,异常将被抛出,自动释放丢失,未初始化的 MYFoo 对象将泄漏。

这里应该怎么做才能防止这种泄漏?

【问题讨论】:

  • 很难说,但我认为您不应该以这种方式使用异常。在 Cocoa 中,您只对程序员错误使用异常——很少需要从异常中恢复,尤其是在对象初始化期间。初始化通常应该成功或返回nil。尝试将您的危险操作放在不同的方法中,并结合使用信号和NSError 来处理失败。

标签: objective-c memory-management memory-leaks


【解决方案1】:

Apple Docs 说最好的做法是不要扔。

处理初始化失败

一般来说,如果有问题 在初始化方法期间,您 应该调用 [self release] 并返回 无。

如果您需要知道发生了什么,您可以init 对象,并让调用者检查某种内部状态以确保对象可用。

【讨论】:

    【解决方案2】:

    一个是 100% 正确的。但是如果你确实需要抛出一个异常并且你确实想在某个地方捕获它(而不是仅仅退出应用程序),你可以将你的初始化包装在 @try { ... } @finally { ... }

    -init
    {
       self = [super init];
       if (self)
       {
           @try
           { 
               // during initialization, something goes wrong and an exception is raised
               @throw...
           }
           @finally
           {
               [self release]; 
           }
       }
       return self;
    }
    

    如果您执行上述操作,您应该记录 init 方法可以抛出异常,因为否则您的代码的其他用户会期望默认行为并且可能不会编写异常安全代码。

    【讨论】:

    • 底线:不要为可恢复的错误抛出异常。 JeremyP 的代码在技术上是正确的,但在语义上违反了 Cocoa/iOS 的模式。由异常引起的泄漏应该是无关紧要的,因为无论如何程序都将立即终止。
    • @bbum:很遗憾,因为至少在理论上,异常优于污染 API,因为必须传递对错误对象的引用并且必须保留特殊的返回值来指示错误。
    • @bbum:另外,考虑到 Cocoa 模式,如果 Cocoa 应用程序的默认行为在检测到未处理的异常时终止,而不是在运行循环中捕获它并继续作为如果什么都没发生。
    • 正确;简单的abort@throw 更好。有很多人——包括我自己——发现异常对于可恢复的错误处理永远不会优越,因为多路径执行的复杂性以及必须在其中处理的所有特殊情况。我做过异常丰富的编程(Java、Python 等),这很痛苦。无论如何,并不是说返回值/错误**很漂亮,但它确实产生了恰好一个执行路径。
    猜你喜欢
    • 2013-05-20
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 2011-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多