构造函数何时抛出异常是正确的?(或者在Objective C的情况下:什么情况下init ` er才应该返回nil?)
在我看来,如果对象不完整,构造函数应该失败——因此拒绝创建对象。也就是说,构造函数应该与它的调用者有一个合同,以提供一个函数和工作对象,在哪些方法可以被有意义地调用?这合理吗?
构造函数何时抛出异常是正确的?(或者在Objective C的情况下:什么情况下init ` er才应该返回nil?)
在我看来,如果对象不完整,构造函数应该失败——因此拒绝创建对象。也就是说,构造函数应该与它的调用者有一个合同,以提供一个函数和工作对象,在哪些方法可以被有意义地调用?这合理吗?
当前回答
对我来说,这是一个有点哲学的设计决策。
拥有实例是非常好的,只要它们存在就有效,从ctor时间开始。对于许多重要的情况,如果无法进行内存/资源分配,则可能需要从ctor抛出异常。
其他一些方法是init()方法,它本身存在一些问题。其中之一是确保init()实际被调用。
一个变体使用惰性方法在第一次调用访问器/突变器时自动调用init(),但这要求任何潜在的调用者都必须担心对象是否有效。(而不是“它存在,因此它是有效的哲学”)。
我也看到过处理这个问题的各种设计模式。例如,可以通过ctor创建初始对象,但必须调用init()来获得包含的、初始化的具有访问器/突变器的对象。
每种方法都有其利弊;我已经成功地使用了所有这些方法。如果不是在创建对象的那一刻就创建现成的对象,那么我建议使用大量的断言或异常,以确保用户在init()之前不会进行交互。
齿顶高
我是从c++程序员的角度写的。我还假设您正确地使用了RAII习惯用法来处理抛出异常时释放的资源。
其他回答
请注意,如果您在初始化器中抛出异常,如果任何代码使用[[[MyObj alloc] init] autorelease]模式,那么您将最终泄漏,因为异常将跳过自动释放。
看这个问题:
在init中引发异常时如何防止泄漏?
如果你正在编写ui控件(ASPX, WinForms, WPF,…),你应该避免在构造函数中抛出异常,因为设计器(Visual Studio)在创建控件时无法处理它们。了解你的控件生命周期(控件事件),尽可能使用惰性初始化。
对我来说,这是一个有点哲学的设计决策。
拥有实例是非常好的,只要它们存在就有效,从ctor时间开始。对于许多重要的情况,如果无法进行内存/资源分配,则可能需要从ctor抛出异常。
其他一些方法是init()方法,它本身存在一些问题。其中之一是确保init()实际被调用。
一个变体使用惰性方法在第一次调用访问器/突变器时自动调用init(),但这要求任何潜在的调用者都必须担心对象是否有效。(而不是“它存在,因此它是有效的哲学”)。
我也看到过处理这个问题的各种设计模式。例如,可以通过ctor创建初始对象,但必须调用init()来获得包含的、初始化的具有访问器/突变器的对象。
每种方法都有其利弊;我已经成功地使用了所有这些方法。如果不是在创建对象的那一刻就创建现成的对象,那么我建议使用大量的断言或异常,以确保用户在init()之前不会进行交互。
齿顶高
我是从c++程序员的角度写的。我还假设您正确地使用了RAII习惯用法来处理抛出异常时释放的资源。
由于部分创建的类可能导致的所有麻烦,我认为永远不会。
如果需要在构造过程中验证某些内容,请将构造函数设为私有并定义一个公共静态工厂方法。如果某些东西无效,该方法可以抛出。但是如果一切都检查出来了,它就调用构造函数,保证不会抛出。
严格地从Java的角度来说,任何时候初始化使用非法值的构造函数时,它都应该抛出异常。这样它就不会被构造成一个糟糕的状态。