Skip to main content
Skip table of contents

Communicator Initialization and Destruction

Creating a Communicator

In C++, you create a communicator by calling the C++ function Ice::initialize, for example:

CPP
int
main(int argc, char* argv[])
{
    Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv);
    // ...
}

initialize accepts a C++ reference to argc and an argument vector argv. The function scans the argument vector for any command-line options that are relevant to the Ice runtime; any such options are removed from the argument vector so, when initialize returns, the only options and arguments remaining are those that concern your application. If anything goes wrong during initialization, initialize throws an exception.

The Ice namespace provides additional initialize overloads to pass other information to the Ice runtime.

You need to call destroy on the returned object when you're done with this communicator, typically just before returning from main. The destroy member function is responsible for cleaning-up the communicator. In particular, in a server, destroy waits for any operation dispatch that are still executing to complete. In addition, destroy ensures that any outstanding threads are joined with and reclaims a number of operating system resources, such as file descriptors and memory.

The general shape of the main function of an Ice-based application is therefore:

CPP
#include <Ice/Ice.h>

int
main(int argc, char* argv[])
{
    int status = 0;
    try 
    {
        // CommunicatorPtr is an alias for std::shared_ptr<Ice::Communicator>
        Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv);
       
        try 
        {
            ... application code ...
 
            communicator->destroy(); // destroy is noexcept
        }
        catch (const std::exception&)
        {
            ... 
            // make sure communicator is destroyed if an exception is thrown
            communicator->destroy();
            throw;
        }      
    } 
    catch (const std::exception& e) 
    {
        cerr << e.what() << endl;
        status = 1;   
    }
    return status;
}

This code is a little bit clunky, as we need to make sure the communicator gets destroyed in all paths, including when an exception is thrown. As a result, most of the time, you should use a helper class to call destroy on your communicator.

Ice::CommunicatorHolder Helper Class

A CommunicatorHolder is a small helper class that you construct with a communicator. It’s then responsible for destroying it.

With a CommunicatorHolder, our typical main function becomes much simpler:

CPP
#include <Ice/Ice.h>

int
main(int argc, char* argv[])
{
    int status = 0;
    try 
    {
        Ice::CommunicatorPtr communicator = Ice::initialize(argc, argv);

        // Schedule destruction of communicator.
        Ice::CommunicatorHolder communicatorHolder{communicator};
        
        ... application code ...
 
        // CommunicatorHolder's destructor calls destroy on the communicator 
        // whether or not an exception is thrown
    } 
    catch (const std::exception& e) 
    {
        cerr << e.what() << endl;
        status = 1;   
    }
    return status;
}

Initialization Data

During the creation of a communicator, initialize configures a number of features that affect the communicator's operation. Once set, these features remain in effect for the life time of the communicator, that is, you cannot change these features after you have created a communicator. Therefore, if you want to customize these features, you must do so when you create the communicator.

The InitializationData class or struct holds all the features (or options) that you can customize when you create a communicator.

See Also
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.