I am writing a pretty simple application in C++ using g++ under Linux and I am trying to throw some raw strings as exceptions (yes, I know, its not a good practise).
I have the following code (simplified):
int main()
{
try
{
throw "not implemented";
}
catch(std::string &error)
{
cerr<<"Error: "<<error<<endl;
}
catch(char* error)
{
cerr<<"Error: "<<error<<endl;
}
catch(...)
{
cerr<<"Unknown error"<<endl;
}
}
And I get Unknow error
on the console. But if I static cast the literal s开发者_如何学Ctring to either std::string
or char *
it prints Error: not implemented
as expected. My question is: so what is the type I should catch if I don't want to use static casts?
You need to catch it with char const*
instead of char*
. Neither anything like std::string
nor char*
will catch it.
Catching has restricted rules with regard to what types it match. The spec says (where "cv" means "const/volatile combination" or neither of them).
A handler is a match for an exception object of type E if
- 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
- the handler is of type cv T or cv T& and T is an unambiguous public base class of E, or
the handler is of type cv1 T* cv2 and E is a pointer type that can be converted to the type of the handler 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
A string literal has type char const[N]
, but throwing an array will decay the array and actually throws a pointer to its first element. So you cannot catch a thrown string literal by a char*
, because at the time it matches, it needs to match the char*
to a char const*
, which would throw away a const (a qualification conversion is only allowed to add const). The special conversion of a string literal to char*
is only considered when you need to convert a string literal specifically.
Try adding const
to the types you're catching, const char*
(possibly const char* const
).
The exact type of a string literal is an array of const characters (const char [15]
for your example, since the NUL terminator is included). The array decays to const char*
when thrown, which is independent of the length.
The type should be const char[15]
or const char*
.
However, while the language does not forbids you throwing any type value, you should not be raising native data types as exception. Instead, you want to raise an std::exception()
instance, or creating your own exception class.
The type of a string literal is char const *
. There's a (deprecated) conversion to char *
provided for backward compatibility with existing code (but you still have to treat it as const
-- any attempt at modification gives UB).
As such, code like this should work:
#include <iostream>
using namespace std;
int main()
{
try
{
throw "not implemented";
}
catch(char const *error)
{
cerr<<"Error: "<<error<<endl;
}
return 0;
}
The problem is that you're trying to catch something that is a const. The following will work:
catch(const char* error) { cerrCheck out the section 2.14.5 of the standard specification, it treats types and kinds of string literals on 3 pages. Don't do what you started to do, just say:
throw std::exception("not implemented");
along with proper
catch (std::exception& pEx)
Is there something wrong with this "normal" approach...?
精彩评论