try
{
if (isfull()==1)
throw "full stack";
else
a[top++] = x;
}
catch (const char *s)
{
cout<<s;
}
Why should we use const in the catch block? If I don't use it, I get this error:
terminate called after throwing an instance of 'char const*'
Aborted (core dumped)
Because you are throwing a string literal, and a string literal is the same as a pointer to constant memory, hence the need for const.
More generally, it's because your catch block isn't catching the exception you're throwing, if you leave off the const.
However, throwing a non-exception type is considered bad form; consider throwing a std::runtime_error or other type derived from std::exception. You can construct most of them with a string, and get the message from the what() property.
You should still catch these by const reference, to prevent copying and modifying the caught object (which isn't a useful thing in any case):
try
{
throw runtime_error( "full stack" );
}
catch( const runtime_error & x )
{
cout << x.what();
}
catch( const exception & x )
{
// catch other exceptions derived from this base class.
}
Your try block throws a const type string: "full stack", which is not meant to be changed in your catch block.
In any case, const char * could not be implicitly casted to char *.
If the catch receive char *s parameter, the content that s point to might be changed by s[...] assignment, which is not acceptable, cause the content("full stack") is constant.
Because you can implicitly assign a variable of less qualifier to more qualifier
But you cant implicitly assign a variable of MORE qualifier to less qualifier
for example
foo(char * p)
fooc(const char * p)
int main(int argc, char agrv[]) {
const char* cp = "hello";
char* p = new char[10];
foo(cp); // ==> compilation error
strcpy(p, cp);
fooc(p) // No probs assigning to a more qualified var
}
Thats why #Joachim Pileborg is right :)
It's not so simple. The question is showing something in C++.
we can assign "const char*" literal to "char*"
char* ss = "full stack"; //ok, although "full stack" looks like a const char*
const char* s2 = "full stack";
char* ss = s2 ; //not ok
for take care of C program, C++ allow : char* ss = "full stack";
by the way. In my VS2005 complier, nothing happend( no coredump).
void main(){
try
{
throw "full stack";
}
catch (char *s)
{
std::cout << s <<std::endl;
}
}
Related
I am trying to create a custom exception class, throw it, and display the error message, but I am doing something wrong, causing the exception to not get thrown and the message to not get printed.
Here's the exception class:
class UnbalancedParenthesesException : public std::exception {
int line_number {0};
public:
UnbalancedParenthesesException(int line_number) :
line_number { line_number }
{}
virtual const char* what() const throw() {
std::string exception_message =
"Papentheses imbalance at line " + std::to_string(line_number) + "\n";
return exception_message.c_str();
}
};
I am trying totry/throw/catch as follows:
void handle_closed_paren(int line_number) {
try {
if (definitely_unbalanced()) {
throw UnbalancedParenthesesException(line_number);
}
} catch (const UnbalancedParenthesesException& e) {
std::out << e.what() << "\n";
}
There is nothing pertinent to this error in the console.
Thanks in advance.
Your what() method is creating a local std::string variable and then returning a pointer to its internal data, which will be left dangling when the std::string goes out of scope and is destroyed when what() exits.
You need to store your error message in a std::string that is a member of the class so it does not go out of scope prematurely. Fortunately, std::exception already has an internal std::string for that purpose. So, instead of formatting the error message in what() itself, you should format it in your derived constructor and pass it to the base class constructor, letting the base what() method return it as-is:
class UnbalancedParenthesesException : public std::exception
{
int mLineNumber;
public:
UnbalancedParenthesesException(int line_number) : std::exception("Parentheses imbalance at line " + std::to_string(line_number)), mLineNumber(line_number) {}
// optional, if the catcher needs access to the value
int lineNumber() const { return mLineNumber; }
};
Your program has undefined behaviour as you are returning the result of c_str() on a std::string that goes out of scope. Anything could happen.
Beyond that, if you're not seeing an exception then one was not thrown, probably because the result of definitely_unbalanced() is falsey.
Step through your program using your debugger.
Well here is my exception code :
class OptionNotFoundError: public std::exception {
public:
OptionNotFoundError(std::string option, int position) throw()
: option(option), position(position) {}
OptionNotFoundError(char option_, int position) throw()
: position(position) { option.push_back(option_); }
virtual ~OptionNotFoundError() throw() {}
virtual const char* what() const throw() {
std::string what_str = "Option '" + option + "' not found in position " + std::to_string(position);
std::cout << what_str.c_str() << std::endl;
return what_str.c_str();;
}
std::string option;
int position;
};
When the exception is thrown, here is what I get in the terminal :
terminate called after throwing an instance of 'Args::OptionNotFoundError'
Option 'c' not found in position 1
what():
So the cout works fine, but… not the return. If I use return "smth" it works fine.
Weirder : if I replace what_str definition with
std::string what_str = "test";
I get
terminate called after throwing an instance of 'Args::OptionNotFoundError'
test
what(): x�zL�
Again, the cout<< works fine. But the return… Not so much. Is this some encoding error ?
return what_str.c_str();;
c_str() returns a pointer to the internal contents of the std::string.
This pointer remains valid only until either
The std::string object gets destroyed.
The std::string object gets modified.
The std::string object from which this c_str() pointer is obtained gets destroyed when your function returns.
This results in undefined behavior.
The const char * that your function returns is not valid. It's pointing to the internal contents of a destroyed object.
For the 1st case, note that what_str is a local variable inside what(), it'll be destroyed when get out of the function scope, then the pointer returned by it becomes dangled, dereference on it leads to UB.
For the 2nd case, returning "smth" works fine, because "smth" is a const char[5], which is a string literal,
String literals have static storage duration, and thus exist in memory for the life of the program.
For the 3rd case,
if i replace what_str definition with
std::string what_str = "test";
It doesn't work, because what_str is still a local std::string, the problem is same with the 1st case.
I have this code that works as expected:
#define MAX_PARAM_NAME_LEN 32
const char* GetName()
{
return "Test text";
}
int main()
{
char name[MAX_PARAM_NAME_LEN];
strcpy(name, GetName());
cout << "result: " << name << endl;
}
If I'd like to store the result to a char * (because some functions within a Frameworks I'm using use only char * as input) without using the strcpy (for practicality and readability of code, and learning too), how could I do? Keeping in const, this works well:
const char* name;
name = GetName();
but I still have const.
Trying to just use char*:
char* name;
name = GetName();
I get invalid conversion from 'const char*' to 'char*'. What's the best habit for this kind of conversion?
The best habit for this kind of conversion is to use std::string throughout your code. Since the framework that you are using takes const char* as its input, you can always pass it the results of c_str() call on your std::string:
std::string GetName() {
return "Test text";
}
int main() {
std::string name = GetName();
int res = external_framework_function(name.c_str());
cout << "result: " << res << " for " << name << endl;
}
A distant second best is using const char* in your code:
const char* name = GetName();
Since the framework that you are using takes const char* you are good here as well.
If you need a non-const pointer, there is no way around copying the string. You can make a function that does it for you, but you would remain responsible for freeing the copies that you get from it:
char* copy(const char* orig) {
char *res = new char[strlen(orig)+1];
strcpy(res, orig);
return res;
}
...
char *name = copy(GetName());
...
delete[] name;
return "Test text"; returns a pointer to a read-only string literal.
If you're using a function that takes a char* as an input, and you have a const char* (such as a read-only string literal), then you ought to supply a deep copy of the string starting at that const char* to such functions.
Else you risk undefined behaviour at runtime if a function attempts to modify a read-only string.
What you currently have is adequate; assuming you can't work with std::string. (If you can work with std::string and all your framework functions take a const char* input, then I'd suggest your refactoring your code to use a std::string, and pass the output of the c_str() method on that string class to your framework functions.)
Finally, if some of your framework functions require a char* then you could always build yourself a small adapter class:
class Adapter
{
public:
Adapter(const& Adapter) = delete; /*don't try to copy me please*/
Adapter& operator=(const Adapter& ) = delete; /*don't try to copy me please*/
Adapter(const char* s) : m_s(::strdup(s))
{
}
~Adapter() /*free memory on destruction*/
{
::free(m_s); /*use free to release strdup memory*/
}
operator char*() /*implicit cast to char* */
{
return m_s;
}
private:
char* m_s;
};
Then for a function void foo(char* c), you can call foo(Adapter("Hello"/*or any const char* */)); and foo can do as it pleases with the char* that's embedded in the anonymous temporary! You could even enhance this class to take a constructor to a char* where in that case only a shallow copy of the pointer is taken (and the destructor doesn't delete the memory).
In C++, the typical way to "drop const" is by using const_cast<>:
char *name = const_cast<char*>(GetName());
This is, of course, frowned upon, ugly and potentially dangerous, since it's really possible that GetName() returns a pointer to something that shouldn't be changed, and then you go and give yourself permission to change it. It's a good way to get very hard to find bugs, in that case.
A workaround is to use a std::string as a temporary holding area; it will mean copying the string but that might be acceptable performance-wise:
std::string s(GetName());
char *name = s.c_str();
This will of course only work if name isn't kept around when s goes out of scope. If that is the case, then you're going to have some form of persistent string storage layer.
You could explicitly cast it. (char*) getName(). But you probably shouldn't. Because the const bit means something like "promise not to change it". So if i have a function void foo(const char* string) I am saiying: "give me a pointer to a string. I won't change it."
And if you declare a variable const char* string = "hello"; You are saying, this string should not be changed. And because you make this promise, the compiler knows, and can make your code more efficient. This is why:
const char* a = "hello";
const char* b = "hello";
(a==b); //is probably true
your compiler knows you won't change a or b so it makes them point to the same address, so it only has to store one "hello" string. If you now go about changing a, b gets also changed, and this is not what you wanted.
So long story short, if you are absolutely sure that the function your calling does not change the string, you can explicitly cast it. (or better, change the function to (const char*) if it's yours).
If your not sure, you will have to make a copy. (Like you are already doing with strcpy()).
Is the following code safely throwing an exception with custom message?
#include <exception>
#include <sstream>
#include <string>
#include <iostream>
int main() {
try {
std::ostringstream msg;
msg << "give me " << 5;
throw std::exception(msg.str().c_str());
} catch (std::exception& e) {
std::cout << "exception: " << e.what();
}
}
With VC++-2008 this gives:
exception: give me 5
But now I wonder why the message "give me 5" from the local object msg is still available in the catch-block? By the time the message is printed both the stream- and the temporary string-object should have been deleted? Btw: This way of generating a message for an exception seems also to work accross several functions and also if new memory is allocated in the catch-block before printing the exception.
Or is it necessary to define a custom exception class with a std::string member in order to safely keep the message until printing it.
It's perfectly safe. The constructor that takes a C string as a single parameter makes a copy of the string. The constructor that takes a C string and a length parameter allow you to specify no memory be allocated and stores a pointer to the string (the length parameter is ignored).
Note that these two constructors are extensions to the std::exception class and are not standard. Also be aware that the constructor that takes a C string as a single parameter is not marked as explicit.
It's OK.
Per §15.1/3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object,
called the exception object.
and §15.1/4:
The memory for the exception object is allocated in an unspecified
way, except as noted in 3.7.4.1. If a handler exits by rethrowing,
control is passed to another handler for the same exception. The
exception object is destroyed after either the last remaining active
handler for the exception exits by any means other than rethrowing...
so after throw expression:
the expression will be copied (new object will be created by copy constructor) and you shouldn't worry about the local object.
About the msg and const char* which you're worrying... here is Microsoft's implementation:
exception::exception(const char * const & _What)
: _Mywhat(NULL), _Mydofree(false)
{
_Copy_str(_What);
//^^^^^^^^^^^^^^^^^
}
void exception::_Copy_str(const char * _What)
{
if (_What != NULL)
{
const size_t _Buf_size = strlen(_What) + 1;
_Mywhat = static_cast<char *>(malloc(_Buf_size));
if (_Mywhat != NULL)
{
_CRT_SECURE_STRCPY(const_cast<char *>(_Mywhat), _Buf_size, _What);
//^^^^^^^^^^^^^^^^^^
_Mydofree = true;
}
}
}
It copies the _What not just storing the pointer.
No, it's not safe, because std::exception doesn't have a constructor taking a char* in the standard. You are using an MS extension. To make it portable and safe, use std::runtime_error instead, to which you can pass a std::string in the ctor.
If a system call fails, I would like to throw an exception that contains the 'errno' relating to the failure. Right now, I use this:
if (bind(...) == -1) {
std::stringstream s;
s << "Error:" << errno << " during bind";
throw std::runtime_error(s.str());
}
That seems clumsy. I cannot directly append an integer to an std::string() - what is the best solution for this? Java has String().append(int), but there's no such facility in std::string. Does everyone write a wrapper around std::string for this purpose?
boost::lexical_cast is useful in this scenario:
throw std::runtime_error("Error:" + boost::lexical_cast<std::string>(errno) + " during bind");
I like using boost::format for this.
std::string msg = boost::str( boost::format("Error: %1% during bind") % errno );
throw std::runtime_error(msg);
One caveat is that if you have a bad_alloc in a catch block, you might hide the previous error. boost::format uses allocations as far as I know, so it could suffer from this. You aren't catching here, so it doesn't exactly apply. It is something to be aware of with error handling though.
You could write your own:
Here is some hints:
class Exception{
public:
Exception(const char* sourceFile, const char* sourceFunction, int sourceLine, Type type, const char* info = 0, ...);
protected:
const char *mSourceFile;
const char *mSourceFunction;
int mSourceLine;
Type mType;
char mInfo[2048];
};
Where type could be:
enum Type
{
UNSPECIFIED_ERROR, //! Error cause unspecified.
.. other types of error...
};
So you can pass string in the usual format.. e.g.
Exception(__FILE__, __FUNCTION__, __LINE__, Type::UNSPECIFIED_ERROR, "Error %d", myInt);