Throwing exceptions from constructors

236,876

Solution 1

Yes, throwing an exception from the failed constructor is the standard way of doing this. Read this FAQ about Handling a constructor that fails for more information. Having a init() method will also work, but everybody who creates the object of mutex has to remember that init() has to be called. I feel it goes against the RAII principle.

Solution 2

If you do throw an exception from a constructor, keep in mind that you need to use the function try/catch syntax if you need to catch that exception in a constructor initializer list.

e.g.

func::func() : foo()
{
    try {...}
    catch (...) // will NOT catch exceptions thrown from foo constructor
    { ... }
}

vs.

func::func()
    try : foo() {...}
    catch (...) // will catch exceptions thrown from foo constructor
    { ... }

Solution 3

#include <iostream>

class bar
{
public:
  bar()
  {
    std::cout << "bar() called" << std::endl;
  }

  ~bar()
  {
    std::cout << "~bar() called" << std::endl;

  }
};
class foo
{
public:
  foo()
    : b(new bar())
  {
    std::cout << "foo() called" << std::endl;
    throw "throw something";
  }

  ~foo()
  {
    delete b;
    std::cout << "~foo() called" << std::endl;
  }

private:
  bar *b;
};


int main(void)
{
  try {
    std::cout << "heap: new foo" << std::endl;
    foo *f = new foo();
  } catch (const char *e) {
    std::cout << "heap exception: " << e << std::endl;
  }

  try {
    std::cout << "stack: foo" << std::endl;
    foo f;
  } catch (const char *e) {
    std::cout << "stack exception: " << e << std::endl;
  }

  return 0;
}

the output:

heap: new foo
bar() called
foo() called
heap exception: throw something
stack: foo
bar() called
foo() called
stack exception: throw something

the destructors are not called, so if a exception need to be thrown in a constructor, a lot of stuff(e.g. clean up?) to do.

Solution 4

It is OK to throw from your constructor, but you should make sure that your object is constructed after main has started and before it finishes:

class A
{
public:
  A () {
    throw int ();
  }
};

A a;     // Implementation defined behaviour if exception is thrown (15.3/13)

int main ()
{
  try
  {
    // Exception for 'a' not caught here.
  }
  catch (int)
  {
  }
}

Solution 5

The only time you would NOT throw exceptions from constructors is if your project has a rule against using exceptions (for instance, Google doesn't like exceptions). In that case, you wouldn't want to use exceptions in your constructor any more than anywhere else, and you'd have to have an init method of some sort instead.

Share:
236,876
lkristjansen
Author by

lkristjansen

Updated on April 08, 2020

Comments

  • lkristjansen
    lkristjansen about 4 years

    I'm having a debate with a co-worker about throwing exceptions from constructors, and thought I would like some feedback.

    Is it OK to throw exceptions from constructors, from a design point of view?

    Lets say I'm wrapping a POSIX mutex in a class, it would look something like this:

    class Mutex {
    public:
      Mutex() {
        if (pthread_mutex_init(&mutex_, 0) != 0) {
          throw MutexInitException();
        }
      }
    
      ~Mutex() {
        pthread_mutex_destroy(&mutex_);
      }
    
      void lock() {
        if (pthread_mutex_lock(&mutex_) != 0) {
          throw MutexLockException();
        }
      }
    
      void unlock() {
        if (pthread_mutex_unlock(&mutex_) != 0) {
          throw MutexUnlockException();
        }
      }
    
    private:
      pthread_mutex_t mutex_;
    };
    

    My question is, is this the standard way to do it? Because if the pthread mutex_init call fails the mutex object is unusable so throwing an exception ensures that the mutex won't be created.

    Should I rather create a member function init for the Mutex class and call pthread mutex_init within which would return a bool based on pthread mutex_init's return? This way I don't have to use exceptions for such a low level object.

  • Éric Malenfant
    Éric Malenfant about 15 years
    It should be noted that exceptions raised from the construction of a sub object can't be suppressed: gotw.ca/gotw/066.htm
  • Martin York
    Martin York about 15 years
    In most situations. Don;t forget things like std::fstream. On failure it still creates an object, but because we are always testing the state of the object normally it works well. So an object that has a natural state that is tested under normal usage may not need to throw.
  • Admin
    Admin about 15 years
    You may be interested in the lengthy discussion on the Google guidelines at groups.google.com/group/comp.lang.c++.moderated/browse_threa‌​d/…
  • endorphin
    endorphin about 15 years
    Interesting discussion. My personal opinion is that you should use exceptions only when you actually design the program's error handling structure to take advantage of them. If you try to do error handling after writing the code, or try to shoehorn exceptions into programs that were not written for them, it's just going to lead to either try/catch EVERYWHERE (eliminating the advantages of exceptions) or to programs crashing out at the least little error. I deal with both every day and I don't like it.
  • thb
    thb almost 12 years
    @Widor: Thank you for reviewing my suggested edit no. 278978. My I ask one more, edit-related question? The answer to which this comment is attached has an outdated hyperlink. To fix it wants to change exactly one character, replacing "#faq-17.2" with "#faq-17.8" in the URL. However, Stackoverflow's software requires that an edit submitted by a low-reputation user like me change at least six characters. Pretty obviously, the broken link wants to be fixed, and it just isn't a six-character fix. Do you know how I can fix it, please?
  • Admin
    Admin over 11 years
    Not really, in this specific case, note that his Mutex destructor will never be called, possibly leaking the pthread mutex. The solution to that is to use a smart pointer for the pthread mutex, better yet use boost mutexes or std::mutex, no reason to keep using old functional-style OS constructs when there are better alternatives.
  • g24l
    g24l over 8 years
    .NET is not C++ , neither JAVA is. The mechanism of throwing are not the same and the costs are different.
  • Carlton
    Carlton almost 8 years
    Very good point. I'm surprised that no other answer addresses this type of leak.
  • cbuchart
    cbuchart about 7 years
    You should be using a std::unique_ptr or similar. Destructor of members is called if an exception is thrown during construction, but plain pointers don't have any. Replace bar* b with std::unique_ptr<bar> b (you'll have to remove the delete b; and add the <memory> header), and run again.
  • zar
    zar over 6 years
    This behavior is quite sensible. If the constructor has failed (was no successfully completed) why should the destructor be called? It has nothing to clean up and if did try to clean up objects which have not even been instantiated properly (think some pointers), it will cause a lot more problems, unnecessarily.
  • Xiaofeng
    Xiaofeng over 6 years
    @zar Yes, the problem is not whether the destructor should be called or not. In this example, clean up should be done before throwing the exception. And I don't mean we cannot throw an exception in the constructor, I just mean the developer should known what he is dong. No good, no bad, but think before doing.
  • Xiaofeng
    Xiaofeng over 6 years
    According to @Naveen's answer, it seems that the memory does freed. But valgrind --leak-check=full ./a.out complains block lost: ERROR SUMMARY: 2 errors from 2 contexts
  • ATL_DEV
    ATL_DEV over 4 years
    Is it possible to make the CreateScaler and TryCreateScaler static?
  • Robin Davies
    Robin Davies about 2 years
    @Martin York: I'm not sure std::fstream is a good example. Yes. It does rely on post-constructor error checking. But should it? It's an awful design that dates from a version of C++ where constructors were forbidden to throw exceptions.