Today, I wanted to show RAII, like this:
#include <iostream>
#include <ostream>
#include <stdexcept>
struct K
{ K (){ ::std::cerr << "K" << ::std::endl; }
~K(){ ::std::cerr << "~K" << ::std::endl; }};
struct R
{ K * k; R() : k{ new K{} }{}
~R() { ::std::cerr << "~R" << ::std::endl; delete k; }};
int main(){ R r{}; throw ::std::runtime_error( "error" ); }
The output was:
K
terminate called after throwing an instance of 'std::runtime_error'
what(): error
This application has requested the Runtime to terminate it in an unusual way.
Please contact the application's support team for more information.
This is the usual process exit code from `abort`.
No ~K nor ~R in sight! Why?
It's unspecified whether stack unwinding happens when there is no
handler for an exception.
In this case, with this compiler, it didn't happen.
For my own little hobby programming I therefore (among many other
semi-good reasons) use a write-it-once-and-be-done-with-it `main`
function that catches any standard exception, as follows:
[code file="cppx/process/invoke_main.hpp"]
#pragma once
// Copyright (c) 2013 Alf P. Steinbach.
#include <rfc/cppx/Type_.h> // cppx::Type_, cppx::Type
#include <rfc/cppx/process/Exit_code.h> //
cppx:
rocess::Exit_code::Enum
#include <functional> // std::function
#include <iostream> // std::clog
#include <stdexcept> // std::exception
#include <system_error> // std::system_error
namespace cppx{ namespace process{
using std::exception;
using std::function;
typedef Type_T_<void()>::T Main_function;
typedef function<Main_function> Main_functor;
typedef cppx::Type_T_<bool( exception const& )>::T Logger_function;
typedef function<Logger_function> Logger_functor;
inline bool stderr_logger( exception const& x )
{
using namespace std;
cerr << "!" << x.what();
if( auto p_syserr = dynamic_cast<system_error const*>( &x ) )
{
cerr << " (error code 0x" << uppercase << hex <<
p_syserr->code().value() << ")";
}
cerr << endl;
return !!clog;
}
inline int invoke_main(
Main_functor const& cpp_main,
Logger_functor const& log = stderr_logger
)
{
try
{
cpp_main();
return Exit_code::success;
}
catch( exception const& x )
{
log( x );
return Exit_code::failure;
}
catch( ... )
{
throw; // Uh oh.
}
}
} } // namespace cppx:
rocess
[/code]
which you can use like this (also this provided in an include file, but
it's questionable whether that can be called a "header"):
[code file="cppx/default_main.impl.hpp"]
// Implementation file.
#include <rfc/cppx/process/invoke_main.hpp>
extern void cpp_main();
auto main() -> int { return cppx:
rocess::invoke_main( &cpp_main ); }
[/code]
whence we get down to the nitty-gritty, namely what you then write in
each using program, like this:
void cpp_main()
{
// blah blah, my "main program" code, may throw
}
#include <rfc/cppx/default_main.impl.hpp>
Of course the include directive can be anywhere, and alternatively it
can be replaced with linking, or even (gasp!) writing the one-liner
`main` -- shown earlier above -- oneself...
Cheers & hth.,
- Alf
PS: There has been an article series about using a standard
write-it-once-and-be-done-with-it `main` in the ACCU Overload Journal. I
haven't read it though. Skimming lightly through one of the articles I
think I saw some not very general interest code there, but it may still
be worth checking out.