Throw New Std::Exception VS Throw Std::Exception

throw new std::exception vs throw std::exception

The conventional way to throw and catch exceptions is to throw an exception object and to catch it by reference (usually const reference). The C++ language requires the compiler to generate the appropriate code to construct the exception object and to properly clean it up at the appropriate time.

Throwing a pointer to a dynamically allocated object is never a good idea. Exceptions are supposed to enable you to write more robust code in the face of error conditions. If you throw an exception object in the conventional manner you can be sure that whether it is caught by a catch clause naming the correct type, by a catch (...), whether it is then re-thrown or not it will be destroyed correctly at the appropriate time. (The only exception being if it is never caught at all but this is a non-recoverable situation whichever way you look at it.)

If you throw a pointer to a dynamically allocated object you have to be sure that whatever the call stack looks like at the point you want to throw your exception there is a catch block that names the correct pointer type and has the appropriate delete call. Your exception must never be caught by catch (...) unless that block re-throws the exception which is then caught by another catch block that does deal correctly with the exception.

Effectively, this means you've taken the exception handling feature that should make it easier to write robust code and made it very hard to write code that is correct in all situations. This is leaving aside the issue that it will be almost impossible to act as library code for client code that won't be expecting this feature.

Why is return throw std::exception() accepted in a void function?

Well, it's because a return statement in a function returning void, can have a void operand:

[stmt.return]/2

The expr-or-braced-init-list of a return statement is called its operand [...] A return statement with an operand of type void shall be used only in
a function whose return type is cv void.

And as you found out yourself, a throw expression has type void. This provision is there to make writing generic code smoother. Consider this:

template<typename T>
T foo() {
return T();
}

The above rule (along with another rule that defines void()) make the above template valid even when instantiated for void.

Should I use std::cerr and exit() instead of throwing an exception?

The main difference between the two, is that you can catch and handle exception (raise with throw). There are two pros for this action:

A. You can throw an exception and handle it without crashing your program.

B. When handling exception, they will automatically call the destructors of your objects. For example:

try {
A a;
throw runtime_error("A"); // Throw exception A
} catch (...) { // Catch exception A & Call a's object destructor.
throw runtime_error("B"); // Throw exception B and crush (if no one else catch it).
}

You want to use the throw and not the exit(1) option, if you think about future working on this code (or if someone else needs to continue your work on this code).

For more details please see: Are destructors run when calling exit()? & Are destructors called after a throw in C++?

Is there any advantages to throw other thing that a std::exception( or derivatives types)

Per §15.1 [except]:

Exception handling provides a way of transferring control and
information from a point in the execution of a thread to an exception
handler associated with a point previously passed by the execution.

The word information illustrates everything, it can be everything such as objects, numbers, ... .

There is nothing in standard that says you must just throw std::exception. In the other words, maybe someone wants to throw his own exception objects.

Maybe someone wants to use exception-handling to handle something far from normal exceptions.

Throwing exceptions without using new in Visual C++?

In C++ exceptions are normally derived from std::exception and are thrown by value, and caught by reference. This way you don't need to manage lifetime (don't need to delete some exceptions after handling and not delete others).

Like throw std::runtime_error(str_error);.

MFC's approach of throwing reference with new predates C++ compiler exception support, so there was a way to throw a pointer exception, but not arbitrary type of exception. It is not recommended for the new code.

There's special smart pointer for exceptions called exception_ptr, it is usually needed to transfer exceptions between threads, not to wrap exceptions being thrown.

If you wrap an exception with unique_ptr, you'll have to catch it wrapped, and this catch will not catch derived exception, because different unique_ptr and not derived from each other, so wrapping exceptions this way is definitely not a good idea.

How to throw std::exceptions with variable messages?

Here is my solution:

#include <stdexcept>
#include <sstream>

class Formatter
{
public:
Formatter() {}
~Formatter() {}

template <typename Type>
Formatter & operator << (const Type & value)
{
stream_ << value;
return *this;
}

std::string str() const { return stream_.str(); }
operator std::string () const { return stream_.str(); }

enum ConvertToString
{
to_str
};
std::string operator >> (ConvertToString) { return stream_.str(); }

private:
std::stringstream stream_;

Formatter(const Formatter &);
Formatter & operator = (Formatter &);
};

Example:

throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData);   // implicitly cast to std::string
throw std::runtime_error(Formatter() << foo << 13 << ", bar" << myData >> Formatter::to_str); // explicitly cast to std::string

Question about operator new overload and exception

The documentation for std::invalid_argument holds the clue:

Because copying std::invalid_argument is not permitted to throw exceptions, this message is typically stored internally as a separately-allocated reference-counted string. This is also why there is no constructor taking std::string&&: it would have to copy the content anyway.

You can see that the string argument is copied by design. This means that re-entering new is pretty much guaranteed if you are throwing this exception in this way.

You should also be aware that malloc can return nullptr which will violate the design of operator new which should either return a valid pointer or throw.

The normal kind of exception to throw in this case is std::bad_alloc. I cannot imagine why you are wanting to throw std::invalid_argument. I thought perhaps you were encountering this issue in a constructor somewhere and decided to test the allocation itself.

Technically you can resolve the problem by passing a default-constructed string as the argument:

// ... but, why would you do this?!! :(
throw std::invalid_argument(std::string()); // will not allocate

Eww, yucky. I recommend you find a more appropriate exception to throw (if you actually need one), or create your own non-allocating exception.

What is the difference between throw and throw with arg of caught exception?

Depending on how you have arranged your exception hierarchy, re-throwing an exception by naming the exception variable in the throw statement may slice the original exception object.

A no-argument throw expression will throw the current exception object preserving its dynamic type, whereas a throw expression with an argument will throw a new exception based on the static type of the argument to throw.

E.g.

int main()
{
try
{
try
{
throw Derived();
}
catch (Base& b)
{
std::cout << "Caught a reference to base\n";
b.print(std::cout);
throw b;
}
}
catch (Base& b)
{
std::cout << "Caught a reference to base\n";
b.print(std::cout);
}

return 0;
}

As written above, the program will output:

Caught a reference to base
Derived
Caught a reference to base
Base

If the throw b is replace with a throw, then the outer catch will also catch the originally thrown Derived exception. This still holds if the inner class catches the Base exception by value instead of by reference - although naturally this would mean that the original exception object cannot be modified, so any changes to b would not be reflected in the Derived exception caught by the outer block.

Why is std::unexpected() not called when I throw an exception in a function specified with an empty throw() specifier?

https://msdn.microsoft.com/en-us/library/vstudio/wfa0edys%28v=vs.120%29.aspx says that:

Visual C++ departs from the ISO C++ Standard in its implementation of
exception specifications.

[...]

[...] if an exception is thrown out of a function marked throw(), the
Visual C++ compiler will not call unexpected [...].

[...]

Due to code
optimizations that might be performed by the C++ compiler (based on
the assumption that the function does not throw any C++ exceptions) if
a function does throw an exception, the program may not execute
correctly.

Additionally, in support of the above, https://msdn.microsoft.com/en-us/library/vstudio/awbt5tew.aspx says:

The C++ Standard requires that unexpected is called when a function
throws an exception that is not on its throw list. The current
implementation does not support this.



Related Topics



Leave a reply



Submit