When is it right for a constructor to throw an exception?

前端 未结 24 821
时光取名叫无心
时光取名叫无心 2020-11-30 16:47

When is it right for a constructor to throw an exception? (Or in the case of Objective C: when is it right for an init\'er to return nil?)

It seems to me that a cons

相关标签:
24条回答
  • 2020-11-30 17:20

    The OP's question has a "language-agnostic" tag... this question cannot be safely answered the same way for all languages/situations.

    The following C# example's class hierarchy throws in class B's constructor, skipping an immediate call to class A's IDisposeable.Dispose upon exit of the main's using, skipping explicit disposal of class A's resources.

    If, for example, class A had created a Socket at construction, connected to a network resource, such would likely still be the case after the using block (a relatively hidden anomaly).

    class A : IDisposable
    {
        public A()
        {
            Console.WriteLine("Initialize A's resources.");
        }
    
        public void Dispose()
        {
            Console.WriteLine("Dispose A's resources.");
        }
    }
    
    class B : A, IDisposable
    {
        public B()
        {
            Console.WriteLine("Initialize B's resources.");
            throw new Exception("B construction failure: B can cleanup anything before throwing so this is not a worry.");
        }
    
        public new void Dispose()
        {
            Console.WriteLine("Dispose B's resources.");
            base.Dispose();
        }
    }
    class C : B, IDisposable
    {
        public C()
        {
            Console.WriteLine("Initialize C's resources. Not called because B throws during construction. C's resources not a worry.");
        }
    
        public new void Dispose()
        {
            Console.WriteLine("Dispose C's resources.");
            base.Dispose();
        }
    }
    
    
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                using (C c = new C())
                {
                }
            }
            catch
            {           
            }
    
            // Resource's allocated by c's "A" not explicitly disposed.
        }
    }
    
    0 讨论(0)
  • 2020-11-30 17:21

    Throw an exception if you're unable to initialize the object in the constructor, one example are illegal arguments.

    As a general rule of thumb an exception should always be thrown as soon as possible, as it makes debugging easier when the source of the problem is closer to the method signaling something is wrong.

    0 讨论(0)
  • 2020-11-30 17:23

    Speaking strictly from a Java standpoint, any time you initialize a constructor with illegal values, it should throw an exception. That way it does not get constructed in a bad state.

    0 讨论(0)
  • 2020-11-30 17:24

    I'm not sure that any answer can be entirely language-agnostic. Some languages handle exceptions and memory management differently.

    I've worked before under coding standards requiring exceptions never be used and only error codes on initializers, because developers had been burned by the language poorly handling exceptions. Languages without garbage collection will handle heap and stack very differently, which may matter for non RAII objects. It is important though that a team decide to be consistent so they know by default if they need to call initializers after constructors. All methods (including constructors) should also be well documented as to what exceptions they can throw, so callers know how to handle them.

    I'm generally in favor of a single-stage construction, as it's easy to forget to initialize an object, but there are plenty of exceptions to that.

    • Your language support for exceptions isn't very good.
    • You have a pressing design reason to still use new and delete
    • Your initialization is processor intensive and should run async to the thread that created the object.
    • You are creating a DLL that may be throwing exceptions outside it's interface to an application using a different language. In this case it may not be so much an issue of not throwing exceptions, but making sure they are caught before the public interface. (You can catch C++ exceptions in C#, but there are hoops to jump through.)
    • Static constructors (C#)
    0 讨论(0)
  • 2020-11-30 17:26

    If you are writing UI-Controls (ASPX, WinForms, WPF, ...) you should avoid throwing exceptions in the constructor because the designer (Visual Studio) can't handle them when it creates your controls. Know your control-lifecycle (control events) and use lazy initialization wherever possible.

    0 讨论(0)
  • 2020-11-30 17:27

    You absolutely should throw an exception from a constructor if you're unable to create a valid object. This allows you to provide proper invariants in your class.

    In practice, you may have to be very careful. Remember that in C++, the destructor will not be called, so if you throw after allocating your resources, you need to take great care to handle that properly!

    This page has a thorough discussion of the situation in C++.

    0 讨论(0)
提交回复
热议问题