The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

C++ temporary objects on throw

I have the following code

throw Exception( string( "File error: Couldn't find " + filename).c_str(), PS_ERROR);

which raises in MSVC (only compiler I have available here) the following

warning C4702: unreachable code

which seems to be indicating to me that the temporary string being created won't be destroyed on unwinding.

is there a better way to format this to avoid the error, and still not become too verbose?
having a named variable for the message just seems a bit excessive, but maybe thats the way it has to be done.
Gorf
Wednesday, September 07, 2005
 
 
I'd rather say that there is code after the throw that cannot be reached.
René Nyffenegger
Wednesday, September 07, 2005
 
 
Please post the context for the line you gave. You shouldn't be getting any errors from that.
Mr Jack
Wednesday, September 07, 2005
 
 
If you have code after your throw statement then remove it, ie:

Throw(Exception ....);
return FALSE; // This is really the part causing the problem
Tony
Wednesday, September 07, 2005
 
 
I agree with those who say that the error is coming from unreachable code after the throw. However, you have another problem. Any code which manipulates the thrown exception will be accessing freed memory.

The pointer returned by c_str() is only valid for the lifetime of the string object, or until the string is modified. In this case, the string object is destroyed as the stack unwinds and the pointer is invalidated before you can catch the exception.

If possible, modify your exception class to store std::string or some other string class rather than pointers to character arrays.
comp.lang.c refugee
Wednesday, September 07, 2005
 
 
It depends on what the constructor of Exception is doing.

If it's making a private copy of the string that's passed in, he's ok. If it's just storing a pointer, then yes, he's hosed.

That exception object really does need to make a copy somehow. Which is unfortunate: what happens if the copy runs out of memory and throws an exception?
Chris Tavares Send private email
Wednesday, September 07, 2005
 
 
Good point. I assumed that the exception class merely stored the pointer.

I suspect that, since the original exception hasn't been thrown yet, an exception generated in constructing it would propagate and the original exception would never be thrown. The other possibility is that the program could behave as if an exception was thrown during stack unwinding. I'm sure it's well-defined, but I'm not sure which it is.
comp.lang.c refugee
Wednesday, September 07, 2005
 
 
For reference Exception constructor is copying the 'string'
code has been simplified

Exception::Exception(LPCSTR str, PROGRAM_STATUS status)
{
  if (str == NULL)
    m_message = NULL;
  else
    m_message = _strdup(str);
  m_status = status;
}


Example 1
there are no local variables
func( bool_test )
{
  if( bool_test )
  {
    // code removed from here
  }
  else
    throw Exception(
      string( "File error: Couldn't find " + filename).c_str(), PS_ERROR);
}

Example 2
it also happens with the following form
if( file_not_found )
  throw Exception(
    ( "Unable to load file: " + filename() ).c_str() );
Gorf
Wednesday, September 07, 2005
 
 
I don't see anything wrong there, aside from errors that you presumably introduced when you simplified the code.

Please post a complete, compilable example that demonstrates the problem. Most likely, you'll discover the cause in the process of stripping it down. If not, perhaps we can help.

Also, what version of MSVC++ are you using?
comp.lang.c refugee
Wednesday, September 07, 2005
 
 
MSVC V6
Release build only - optimized to maximize speed.
Warning Level 4.

Hmmm, if an archive could be attached!  I'll see what I can do about providing some complete sample code that shows the error.
Gorf
Thursday, September 08, 2005
 
 
Please excuse the somewhat nasty naming/formating and other general bodgieness of the example I hacked together to show the problem.

#include <Windows.h>
#include <string>

class Exception 
{
public:
Exception(LPCSTR str)
{
  if (str == NULL)
    m_message = NULL;
  else
    m_message = _strdup(str);
}
virtual ~Exception();

char * message( ) const
{
    return m_message;
}

private:
char * m_message;

};

class Xyzzy
{
public:
Xyzzy( std::string ref, std::string filename )
: m_filename( filename )
{
  if( m_filename.empty() )
    throw Exception( std::string( "BLAH!" + ref).c_str() ); // MSVC6 reports 7 times warning C4702: unreachable code
}
private:
    std::string m_filename;
};

int main(int argc, char* argv[])
{
  try
  {
    Xyzzy foo( "a", "" );

    std::string filename("joe");
    throw Exception( std::string( "BLAH!" + filename).c_str() ); // no warning here
  }
  catch( Exception & e )
  {
    MessageBox( NULL, e.message(), "Exception", 0);
  }
  return 0;
}
Gorf
Friday, September 09, 2005
 
 
I get no warnings when compiling that code on MSVC6 (with warning level 4) - are you sure that code demonstrates it? Why don't you post the _actual_ code giving you the error?
Mr Jack
Friday, September 09, 2005
 
 
Xyzzy foo( "a", "" ) means that filename is empty so is m_filename so the exception is always thrown so the construction is never finished. Maybe with the optimisation the compiler is doing enough to figure this out.

It compiles OK in VS2003 at W4 release by the way.
Tony
Friday, September 09, 2005
 
 
Compiling with default release build settings on VC++ 6.0 and with warning level 4, I get lots of warnings, including those listed below. (I have trimmed all the warnings resulting from the header files.)

There are no warnings at all with a debug build at warning level 4.

I can't explain for certain about the unreachable code, but I suspect the optimizer has spotted some execution paths that can never be followed and has optimized them away, and is then warning about what it has done. If I reduce the optimization level from "Maximize Speed" to "Default" then the unreachable code warnings disappear.

--------------------Configuration: xyzzy - Win32 Release--------------------
Compiling...
xyzzy.cpp
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(39) : warning C4100: 'argv' : unreferenced formal parameter
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(39) : warning C4100: 'argc' : unreferenced formal parameter
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(43) : warning C4710: function '__thiscall Xyzzy::Xyzzy(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::al
locator<char> >)' not inlined
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(43) : warning C4710: function '__thiscall std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >(char const *,
class std::allocator<char> const &)' not inlined
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4710: function 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::operator+(char const *,class std::basic_string<char,struct std::char_traits<char>,c
lass std::allocator<char> > const &)' not inlined
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(46) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(47) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4710: function 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl std::operator+(char const *,class std::basic_string<char,struct std::char_traits<char>,c
lass std::allocator<char> > const &)' not inlined
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
D:\Test\Cplusplus\xyzzy\xyzzy.cpp(33) : warning C4702: unreachable code
Linking...

xyzzy.exe - 0 error(s), 96 warning(s)
Ian Boys Send private email
Saturday, September 10, 2005
 
 
By the way, I commented out the virtual destructor declaration so it would link without error.
Ian Boys Send private email
Saturday, September 10, 2005
 
 
Thanks for confirming Ian.
I accidently left out the implementation of the destructor upon rearranging to a single file and seeing that I still had the compiler error.
I actually had something like
virtual ~Exception()
{
  if( NULL != m_message )
    free( m_message );
};

Tony
I understand the sentiment of not doing the rest of the constructor, however in the original case the second option would be a variable, initialised as read from another file thus not available to be optomised out, and there is nothing else after it in the constructor in any case - perhaps it doesn't bother checking.

Mr Jack
The code without simplification is large.
the simplest original piece I could send makes use of the xerces XML C++ interface, and so while the code is 'simple' you would also have to download xerces from the web and compile it also.
It would also add extra complexity which is not necessary to show the case.

Did you compile in release mode?
Gorf
Sunday, September 11, 2005
 
 
No, I didn't compile in Release. I get the errors when I do. It seems to relate to inlining. Frankly, I'd disregard it as a fault in MSVC6 and not worry about it.
Mr Jack
Tuesday, September 13, 2005
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz