try {
char message = "Error!";
throw message;
}
Catch site.
catch (char* &e) {
court << e << endl;
return 0;
}
Does anyone know how to fix this?
I want to display an error message but am required to do so with a C-string.
You are not throwing the string or the array. Because of array-to-pointer decay you are throwing a pointer to the first element of the message array. You are catching that pointer just fine. Unfortunately during stack unwinding the array into which the pointer is pointing is destroyed since it is a local variable in the if block and your catch block is outside that if block. So you are then trying to dereference a dangling pointer in cout << *e << endl;, causing undefined behavior.
In theory you can do
const char* message = "Error! Invalid data for: Total Crew.";
throw message;
or
throw "Error! Invalid data for: Total Crew.";
to throw pointers to the string literals, which live until the end of the program, but that is really bad practice. You should instead write a class inherited from std::exception or another standard library exception class like std::invalid_argument and then throw an instance of your exception class. This way you can make catch clauses to handle specific types of exceptions, not just generic char* that could mean anything.
Also cout << *e << endl; would print only the first character of the string, even if there wasn't the lifetime issue. You probably meant cout << e << endl; instead.
but am required to do so with a C-string.
There is no good reason for that, except as far as all string literals are C-style strings. The exception classes inherited from std::exception allow one to provide a string argument to store in the exception object via the constructor and to retrieve it with the .what() member function in the catch handler.
You could even use them directly, without inheriting your own exception class:
if (totalCrew <=0) {
throw std::invalid_argument("Error! Invalid data for: Total Crew.");
}
//...
catch (const std::invalid_argument& e) {
cout << e.what() << endl;
cout << "Line: " << line << endl;
return 0;
}
Related
I have this function, where I'm trying to return a const char*, but when I try to output the returned value, I get garbage value;
virtual const char* what() const noexcept
{
std::stringstream s;
if(m_id > -1)
s << m_message << " with id " << m_id << " does not exist";
else
s << m_message << " with name " << m_name << " does not exist";
//until now it works fine
std::string tmp = s.str();
const char* temp = tmp.c_str();
return temp; //after I execute this command, the value is deleted.
}
when I try to print:
catch (std::exception& e)
{
std::cout << e.what() << std::endl;
}
I get this (different every time..) :
▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌▌╢Pⁿש▌'
What am I doing wrong?
You are returning a pointer to the internal char data of a local std::string object that is destroyed when the function exits, thus the returned pointer is left dangling, pointing at invalid memory. Trying to access the data afterwards is undefined behavior.
Normally, you would have two choices to fix that:
return a std::string instead of a char* pointer.
allocate the char data dynamically, and then make the caller free it when done using it.
However, in this case, you are overriding the std::exception::what() method, so neither of those options are viable. What you will have to do instead is store your char data in a std::string member of your derived class, and then you can return a char* pointer to its data, eg:
private:
std::string m_what;
myException::myException(...)
{
...
std::stringstream s;
if (m_id > -1)
s << m_message << " with id " << m_id << " does not exist";
else
s << m_message << " with name " << m_name << " does not exist";
m_what = s.str();
}
virtual const char* what() const noexcept
{
return m_what.c_str();
}
If you derive your exception class from std::runtime_error instead of std::exception directly, this is already handled for you. std::runtime_error takes a string in its constructor, and overrides what() to return that string's data.
The problem is that tmp is local to the function what and you're returning a pointer to that local's internal array. This is a problem because the local will be destroyed once the function exits. That is, the pointer that you return is a dangling pointer. Using that dangling pointer(which you do when you wrote std::cout << e.what() << std::endl;) is undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior.
So the output that you're seeing(maybe seeing) is a result of undefined behavior. And as i said don't rely on the output of a program that has UB. The program may just crash.
So the first step to make the program correct would be to remove UB. Then and only then you can start reasoning about the output of the program.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.
Please consider the following code:
throw my_exception() << "The error " << error_code << " happened because of " << reasons;
The supporting code would be something like:
class my_exception
{
public:
template <typename T>
my_exception & operator << (const T & value)
{
// put the value somewhere
return *this;
}
// etc.
};
Is there any reason that would make such throw dangerous, or simply inefficient compared to the alternative below?
std::stringstream s;
s << "The error " << error_code << " happened because of " << reasons;
throw my_exception(s.str());
You're constructing the exception object via several function calls (the operator<< overloads), all of which happen before the exception is thrown. This is no different than normal program execution.
The only potential issue is you can get a different exception thrown if something in the building of the exception object throws (like if there isn't enough memory available to hold the built error string).
So there's nothing inherently dangerous about doing this.
I'm currently playing around with exception types and I've noticed something odd when attempting to re-throw caught exceptions.
From the C++ specification, I know that throw actually produces a copy of the object you're attempting to throw, so you will end up slicing any residual derived-type information that you caught.
To avoid this, I have seen suggestions to re-throw a pointer to the original exception as the actual original object will then not have its derived portion removed.
However, the simple example program I've written below would seems to not work that way:
#include <exception>
#include <iostream>
#include <typeinfo>
class derived_exception : public std::exception { };
void rethrowException(bool anonymise) {
try {
throw derived_exception();
} catch(const std::exception& e) {
std::cout << "Caught: " << typeid(e).name() << " (std::exception)" << std::endl;
if(anonymise) {
throw;
} else {
throw &e;
}
}
}
int main() {
std::cout << "Re-throwing caught exception..." << std::endl;
try {
rethrowException(false);
} catch(const derived_exception* e) {
std::cout << "Re-caught: " << typeid(e).name() << " (derived_exception)" << std::endl;
} catch(const std::exception* e) {
std::cout << "Re-caught: " << typeid(e).name() << " (std::exception)" << std::endl;
}
std::cout << std::endl << "Re-throwing anonymous exception..." << std::endl;
try {
rethrowException(true);
} catch(const derived_exception& e) {
std::cout << "Re-caught: " << typeid(e).name() << " (derived_exception)" << std::endl;
} catch(const std::exception& e) {
std::cout << "Re-caught: " << typeid(e).name() << " (std::exception)" << std::endl;
}
}
With the output of ./example:
Re-throwing caught exception...
Caught: 17derived_exception (std::exception)
Re-caught: PKSt9exception (std::exception)
Re-throwing anonymous exception...
Caught: 17derived_exception (std::exception)
Re-caught: 17derived_exception (derived_exception)
You can successfully re-cast the pointer and retrieve the derived type information, but the pointer type is still initially sliced.
Is there any way around this without catching the base and attempting to dynamic_cast back?
Thanks
1. What throw throws?
C++14 Standard
5.17 Throwing an exception
A throw-expression with no operand rethrows the currently handled exception.
15.1 Throwing an exception
Throwing an exception copy-initializes a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler.
For statement throw;, it will re-throw the current exception object derived_exception().
For statement throw &e;, it will create a temporary object of type std::exception *, effectively equivalent to throw (std::exception *except_obj = &e);.
2. Which catch catches?
C++14 Standard
15.1 Throwing an exception
Throwing an exception copy-initializes a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler.
15.3 Handling an exception
A handler is a match for an exception object of type E if
[3.1] The handler is of type cv T or cv T& and E and T are the same type (ignoring the top-level cv-qualifiers), or
[3.2] the handler is of type cv T or cv T& and T is an unambiguous public base class of E, or
[3.3] the handler is of type cv T or const T& where T is a pointer type and E is a pointer type that can be converted to T by either or both of
a standard pointer conversion (4.10) not involving conversions to pointers to private or protected or ambiguous classes
a qualification conversion, or
[3.4] the handler is of type cv T or const T& where T is a pointer or pointer to member type and E is std::nullptr_t.
The handlers for a try block are tried in order of appearance.
When anonymise == true:
throw; is executed, thus re-throw exception object derived_exception(), then to pick an entry point among:
catch(const derived_exception& e),
and catch(const std::exception& e).
From Standard 15.3-3-3.2, we know derived_exception() matches catch(const derived_exception& e). Thus the output is:
Re-caught: 17derived_exception (std::exception)
When anonymise == false:
throw &e; is executed, thus create a temporary exception object of type std::exception *, then to pick an entry point among:
catch(const derived_exception* e),
and catch(const std::exception* e).
We can't pick the former one. Because none of the four rules in Standard 15.3-3 say std::exception * is considered a match of const derived_exception *.
So, the later catch is picked. We see output:
Re-caught: PKSt9exception (std::exception)
( You may want to argue about the third rule [3.3], but neither standard pointer conversion nor qualification conversion supports conversion from baseclass pointer to subclass pointer, down-casting must be done explicitly, like usingdynamic_cast<T>(). )
3. In your question
From the C++ specification, I know that throw actually produces a copy of the object you're attempting to throw,
Right.
so you will end up slicing any residual derived-type information that you caught.
Right if you use value type instead of reference or pointer in catch. One example is
try {
throw derived_exception();
} catch (const std::exception e) {
...
}
From Standard 15.1-3, we know here e will be initialized with derived_exception(). In effect, it's like executing e = derived_exception();. I can't find any reason to use this form, though.
I have seen suggestions to re-throw a pointer to the original exception as the actual original object will then not have its derived portion removed.
By replacing typeid(e).name() with typeid(*e).name(), we can see the original object is not sliced:
catch (const std::exception *e)
{
std::cout << "Re-caught: " << typeid(*e).name() << " (std::exception)"
<< std::endl;
}
// Re-caught: 17derived_exception (std::exception)
I am learning C++ and I am experiencing when I try and create my own exception and throw them on Linux.
I've created a small test project to test my implementation and below is my exception class header file.
class TestClass : public std::runtime_error
{
public:
TestClass(char const* const message) throw();
virtual char const* what() const throw();
};
The source file for the exception class is
using namespace std;
TestClass::TestClass(char const* const message) throw()
: std::runtime_error(message)
{
}
char const * TestClass::what() const throw()
{
return exception::what();
}
In my main app, I am calling a function which throws my exception and catches it in a try/catch as follows:
void runAFunctionAndthrow();
/*
*
*/
int main(int argc, char** argv) {
try
{
cout << "About to call function" << endl;
runAFunctionAndthrow();
}
catch (TestClass ex)
{
cout << "Exception Caught: " << ex.what() << endl;
}
return 0;
}
void runAFunctionAndthrow()
{
cout << "going to run now. oh dear I need to throw an exception" << endl;
stringstream logstream;
logstream << "This is my exception error. :(";
throw TestClass(logstream.str().c_str());
}
When I run I'm expecting to get the following output:
About to call function
Going to run now. oh dear I need to throw an exception
Exception Caught: This is my exception error. :(
Instead what I am getting is
About to call function
going to run now. oh dear I need to throw an exception
Exception Caught: std::exception
Notice the last line it says std::exception instead of my actual exception message "This is my exception error".
Why is this, it works OK on Windows but on Linux it does this.
From what I've seen on various posts what I've done is correct so what am I missing.
Your what() returns:
return exception::what();
The return value from std::exception::what() is specified as follows:
Pointer to a null-terminated string with explanatory information.
That's it. Nothing more, nothing else. The text you're showing certainly qualifies as an "explanatory information". And this is the only requirement for the return value of what() (except for one other one which is not germane here).
In other words, C++ does not guarantee the exact contents of what you get with what(). what() you see is what() you get, as the saying goes.
If you want your exception to describe itself, in some way, it's up to you to implement that, as part of your what().
You need your own implementation of what() method or use std::runtime_error::what() as written in comments
Say:
class TestClass : public std::runtime_error
{
std::string what_message;
public:
const char* what() override
{
return what_message.c_str();
}
};
Also, better use noexcept instead of throw() and only after you read about them - link.
And in your try-catch:
catch (const TestClass& myException)
Instead of catch(TestClass myException) - otherwise you do an implicit copy which can potentially result in an exception throw. It also breaks the polymorphism: if you want to catch pure virtual interface implementation instance, you would need to use a reference.
You need a way to specify a custom error message to std::exception which afaik is not allowed. See this for a possible solution.
First of most of the info about the answer had been given by Sam Varshavchik
But I want to add one thing
When throwing and catching A good rule is
"Throw by value catch by reference "
So your throw was fine as:
void runAFunctionAndthrow()
{
cout << "going to run now. oh dear I need to throw an exception" << endl;
stringstream logstream;
logstream << "This is my exception error. :(";
throw **TestClass(logstream.str().c_str())**;
}
used an implicit conversion to TestClass and then it got passed by value.
the Key point in that rule is to minimize memory allocating handling between different stack frames
your catch on the other hand dosen't follow the rule (since you catch by value):
catch (TestClass ex)
{
cout << "Exception Caught: " << ex.what() << endl;
}
the catch should be (const TestClass& ex)
the key point in this rule is implicit conversion between base class and derived class.
I am coding using a very simple exception in C++.
but that is not working as i expect.
and i don't know why even though in debugging mode.
i attach a picture that show variable in eclipse debugging mode at the catch point.
i excepted that the code flow will go into if statement but it go into else statement.
as this problem is too simple, i think that i have misunderstood on handling exception, please fix my understanding.
throw "connection fail";
.
catch(const char* e){
if(e == "connection fail"){
clients.erase(client);
continue;
}else{
std::cout << e << std::endl;
assert(NULL);
}
}
You're lucky that the code didn't work as expected, there's a good chance it might have, and then broken when you rebuilt your code a long time from now.
if(e == "connection fail"){
The problem above is that you're comparing two pointers (that point to two distinct string literals), and not the strings themselves as you expect it to. The reason I said it might've worked is because compilers are allowed to pool string literals, meaning it would've used the same copy of the string literal in both places, and the check would've passed, leading you to believe that the code works correctly. Of course, there's no guarantee that that would always happen, and your code might break silently one day when you recompile.
To actually compare the strings, either use strcmp, or convert one of the operands to std::string.
try {
throw "connection fail";
} catch( char const *e ) {
if(std::string(e) == "connection fail") {
std::cerr << "caught: " << e << std::endl;
}
}
A better solution is to throw types that derive from std::exception instead. I'd change your code to:
try {
throw std::runtime_error("connection fail");
} catch( std::exception const& e ) {
std::cerr << "caught: " << e.what() << std::endl;
}
Please don't throw const char*, that makes no sense!
throw std::runtime_error("My Error");
catch (const std::runtime_error& e)
or create your own exception that contains variables which indicate exception detail, or different object types which indicate the problem! Then you don't need to do any string comparison.
You can't compare C-style strings with ==, you must use strcmp. Most of the time.
The == is only comparing the pointer addresses. In this case you have two strings so they're at different addresses, even though they may contain the same characters in the string.
You can make the == comparison work if you can ensure that both strings are actually the same location in memory. Here's a way to make it work:
static const char * connection_fail = "connection fail";
throw connection_fail;
catch(const char* e){
if(e == connection_fail){
// ...
The better solution all around would be to not throw strings, but throw objects derived from std::exception instead. These contain a what() method that can be used to get a string describing the error.