Overview
Features
Download
Documentation
Community
Add-Ons & Services

Application::run()

Please post support and help requests here.

Application::run()

Postby Edsoon » 26 Mar 2013, 19:36

/// Runs the application by performing additional initializations
/// and calling the main() method.
///
/// First calls initialize(), then calls main(), and
/// finally calls uninitialize(). The latter will be called
/// even if main() throws an exception. If initialize() throws
/// an exception, main() will not be called and the exception
/// will be propagated to the caller.

int Application::run()
{
int rc = EXIT_CONFIG;
try
{
initialize(*this);
rc = EXIT_SOFTWARE;
rc = main(_unprocessedArgs);
uninitialize();
}
catch (Poco::Exception& exc)
{
logger().log(exc);
}
catch (std::exception& exc)
{
logger().error(exc.what());
}
catch (...)
{
logger().fatal("system exception");
}
return rc;
}

But method uninitialize() not called if method main throws exception. If this happens our program can not complete normally.
Edsoon
 
Posts: 5
Joined: 19 Jul 2012, 16:26

Re: Application::run()

Postby rakesh » 26 Mar 2013, 23:09

Why not move it outside the try block?
rakesh
 
Posts: 78
Joined: 13 Apr 2011, 17:43
Location: Chicago

Re: Application::run()

Postby alex » 27 Mar 2013, 03:27

It seems there's a discrepancy between documentation and implementation in two ways - first, uninitialize() is not guaranteed to be called and second, exceptions are not propagated. To ensure uninitialize() gets called, it should be moved out of the try/catch block, and put into it's own before the last line, something like this:

Code: Select all
try
{
  initialize(*this);
  rc = EXIT_SOFTWARE;
  rc = main(_unprocessedArgs);
}
// ...
catch (...)
{ logger().fatal("system exception"); }

try
{ uninitialize(); }
catch (...)
{ logger().fatal("Could not uninitialize."); }

return rc;
}
alex
 
Posts: 1130
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Application::run()

Postby alex » 31 Mar 2013, 00:04

This was fixed for 1.5.2 release
alex
 
Posts: 1130
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Application::run()

Postby Edsoon » 31 Mar 2013, 15:39

alex wrote:This was fixed for 1.5.2 release

Now, as i understand, function Application::run() can throw exception in calling function `main`. It's not good. One of the benefits of using a poco framework is that the `main` function only creates an object and calling method `run` :
int main ()
{
Object obj;
return obj.run;
}

You can solve the problem differently:

int Application::run()
{
int rc = EXIT_CONFIG;
try
{
initialize(*this);
rc = EXIT_SOFTWARE;
rc = main(_unprocessedArgs);
uninitialize();
}
catch (Poco::Exception& exc)
{
uninitialize();
logger().log(exc);
}
catch (std::exception& exc)
{
uninitialize();
logger().error(exc.what());
}
catch (...)
{
uninitialize();
logger().fatal("system exception");
}
return rc;
}

OR

int Application::run()
{
int rc = EXIT_CONFIG;
try
{
initialize(*this);
rc = EXIT_SOFTWARE;
rc = main(_unprocessedArgs);
}
catch (Poco::Exception& exc)
{
logger().log(exc);
}
catch (std::exception& exc)
{
logger().error(exc.what());
}
catch (...)
{
logger().fatal("system exception");
}
uninitialize();
return rc;
}

And declare the function `uninitialize` as function which can not throw exception :
void Application::uninitialize() throw() {
//...
}
Throw exception in function uninitialize as bad as throwing exceptions in destructor.
Edsoon
 
Posts: 5
Joined: 19 Jul 2012, 16:26

Re: Application::run()

Postby alex » 31 Mar 2013, 17:12

Edsoon wrote:Now, as i understand, function Application::run() can throw exception in calling function `main`.

Yes, and it behaves exactly as documented - it throws only if initialize/uninitialize throw; uninitialize() is called only if initialize() call was completed.

Edsoon wrote:You can solve the problem differently:

Your solution does the same thing as the fix, except for trapping initialize() exceptions (which is in discrepancy with documentation). Why would you want to call uninitialize() if initialize() call did not complete? What exactly is the purpose of calling uninitialize in every catch block?

Edsoon wrote:Throw exception in function uninitialize as bad as throwing exceptions in destructor.

No, it is not. Application::uninitialize() is not called automatically on scope exit.
alex
 
Posts: 1130
Joined: 11 Jul 2006, 16:27
Location: United_States

Re: Application::run()

Postby Edsoon » 31 Mar 2013, 20:24

alex wrote:uninitialize() is called only if initialize() call was completed.

Yes, the same behavior have classes in c++ (destructor called only if constructor completed). But if constructor is not completed compiler destroys all objects which created in constructor.
In your case, the compiler does not "destroys" objects automatically , you should do it independently (by calling uninitialize).

alex wrote:Your solution does the same thing as the fix, except for trapping initialize() exceptions (which is in discrepancy with documentation). Why would you want to call uninitialize() if initialize() call did not complete? What exactly is the purpose of calling uninitialize in every catch block?

If function initialize () throws exception in the end of function and some objects already initialized (opened file or something else) ? Function uninitialize() should uninitialize objects which initialized in function initialize() (close file or something else).
I showed that the function uninitialize() must be called always.

alex wrote:No, it is not. Application::uninitialize() is not called automatically on scope exit.

You provide possibility to throw exception from uninitialize() , thus providing places for potential errors related with uninitialize.
Edsoon
 
Posts: 5
Joined: 19 Jul 2012, 16:26

Re: Application::run()

Postby alex » 31 Mar 2013, 22:49

Edsoon wrote:But if constructor is not completed compiler destroys all objects which created in constructor.

Since we're talking analogy to C++ then let's take into consideration that, just like initialize/uninitialize, constructor/destructor are functions and the latter does not get called unless the former has completed.
Edsoon wrote:compiler does not "destroys" objects automatically , you should do it independently (by calling uninitialize).

you can do it independently without calling uninitialize() or you can call uninitialize() explicitly from your code if initialize() throws.
Edsoon wrote:You provide possibility to throw exception from uninitialize() , thus providing places for potential errors related with uninitialize.

That argument can be applied to any arbitrary function that may throw. It is well documented what the code does. If you are not happy, then fork, work and send pull request. At this point, I'm not yet convinced that there's something wrong with the most recent change and it will go into 1.5.2 as it is.
alex
 
Posts: 1130
Joined: 11 Jul 2006, 16:27
Location: United_States


Return to Support

Who is online

Users browsing this forum: No registered users and 1 guest