Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::exception using message from local object

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.

like image 771
coproc Avatar asked May 21 '13 19:05

coproc


3 Answers

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.

like image 105
Captain Obvlious Avatar answered Oct 07 '22 10:10

Captain Obvlious


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.

like image 45
masoud Avatar answered Oct 07 '22 12:10

masoud


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.

like image 3
Ulrich Eckhardt Avatar answered Oct 07 '22 12:10

Ulrich Eckhardt