6

I am C# programmer but now I want to get more into C++.
I know the basics of C++ but I don't know how to handle errors.

For example: I am writing a library. I create an constructor which requests an integer as an argument.
If that integer is bigger than 50, it is an error. In C# I would throw an ArgumentOutOfRange exception, but what should I do in C++?

David Haim
  • 25,446
  • 3
  • 44
  • 78
Florian
  • 5,918
  • 3
  • 47
  • 86
  • possible duplicate of [How to handle failure in constructor in C++?](http://stackoverflow.com/questions/4989807/how-to-handle-failure-in-constructor-in-c) – BЈовић May 24 '13 at 11:56
  • @stefan, in C++ one does not use exceptions to control program flow. driving away from question - it may be a good idea to make a factory, that does all required checks and avoids using exceptions for wrong reasons – ShPavel May 24 '13 at 12:15

4 Answers4

22

In C# I would throw an ArgumentOutOfRange exception but what should I do in c++?

First you should consider if that should not be a precondition of your function, leaving the responsibility of checking whether the value is in range to the caller.

If you decide for this option, then invoking the function with an out-of-range value would be undefined behavior, and inside the function you could just have a debug assertion to help you spot possible misuses - without the need of throwing any exception.

If you decide that the function should have a wide contract, on the other hand, and react in a well-defined way by throwing an exception when the argument is outside the permitted range, then you could throw an std::out_of_range exception.

For example: I am writing a libary [...]

If you are writing a library, meaning that you do not know the exact requirements of your clients in terms of performance and robustness, you may consider providing two such functions - one with a wide contract that throws exceptions, and one with a narrow contract that assumes the client provides meaningful input.

This way, the user of your library could decide based on their use cases whether or not it is OK to pay for the overhead of checking the correctness of the input each time your function is called.

This is, for instance, the strategy adopted by the C++ Standard Library for std::vector, which provides a non-throwing operator[] with a narrow contract for accessing elements of the collection based on the index (this function has undefined behavior if the index is out-of-bounds), and a member function at() that performs index checking and throws an exception if the index is out-of-bounds.

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • 4
    Good post all around. +1 Assertion (pre/post conditions), std::vector examples, and options. – Freddy May 24 '13 at 11:56
  • @Freddy: Glad you found it helpful – Andy Prowl May 24 '13 at 11:58
  • 1
    your long and abosultetly correct answer about exceptions may lead OP to the wrong side of force. Kerrek SB's next answer should also be considered in this situation, to avoid comments, like from @stefan to original question – ShPavel May 24 '13 at 12:13
  • What is a narrow or wide contract? – Pedro Reis Feb 12 '17 at 07:48
  • @AndyProwl By (http://stackoverflow.com/questions/30222608/c-noexcept-for-a-function-not-throwing-exceptions-but-can-cause-a-memory-fail) I assume that a function with a wide contract never has an undefined behaviour (so, it never throws?) while a narrow one may be undefined depending in the calling conditions. But you've wrote: "one with a wide contract that throws exceptions"... Can you explain? Thanks! – Pedro Reis Feb 14 '17 at 12:03
4

It depends on whether an integer larger than 50 could possibly be passed to the constructor as part of normal program flow, or whether that's an exceptional condition. But in general the only way to have object construction fail is by throwing an exception.

Your user code might look like this:

int n = parse_user_input()

if (n < 50)
{
    Foo x(n);
    x.do_cool_stuff();
}
else
{
    // report user error
}

That is, you don't actually use exceptions for normal control flow. With that sort of code pattern, it would be perfectly fine for Foo::Foo(int) to throw an exception if the argument were out of range.

You can find useful standard exception classes in <stdexcept>.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
3

The same thing as in C#: throw an exception. This is the only way to prevent an object from being constructed.

std::invalid_argument is a good standard choice regarding what to throw.

Jon
  • 428,835
  • 81
  • 738
  • 806
0

From the C++ FAQ: [17.8] How can I handle a constructor that fails?

Excerpt:

Throw an exception.

Constructors don't have a return type, so it's not possible to use return codes. The best way to signal constructor failure is therefore to throw an exception. If you don't have the option of using exceptions, the "least bad" work-around is to put the object into a "zombie" state by setting an internal status bit so the object acts sort of like it's dead even though it is technically still alive.

So, throwing std::invalid_argument or std::out_of_range would be perfectly acceptable for your situation. You could also throw a custom exception if that would be beneficial in your situation. In the C++ FAQ see: [17.12] What should I throw?

DavidRR
  • 18,291
  • 25
  • 109
  • 191