Delegating Constructors in C++11

Here’s some code that tries out C++ 11 delegating constructors.  These were announced as part of Visual Studio in the November CTP and avoid the need to refactor common code out of constructors into an “init” function.  There are examples of their use in Stephan Levavej’s excellent video series too.

class Request
{
public:
  enum class Priority{ High, Medium, Low };
  static const Priority defaultPriority(){ return Priority::Low; }

  // Constructor with all parameters fully specified
  Request( Priority priority, const std::string& requestId ) :
      m_priority( priority ),
      m_requestId( requestId )
  {
    std::cout 
    << "Request( Priority priority, const std::string& requestId ) called: "
    << "RequestId " << m_requestId << ", "
    << "Priority " << toString( m_priority ) << "\n";
  }

  // Delegate to fully specified constructor above
  Request( const std::string& requestId ) : 
    Request( defaultPriority(), requestId )
  {
    std::cout 
      << "Request( const std::string& requestId ) called: "
      << "RequestId " << requestId << "\n";
  }

  // Contrived example to demonstrate chaining delegating constructors
  Request( const std::vector<int>& requestId ) : 
    Request( toString( requestId ) )
  {
    std::cout << "Request( const std::vector<int>& requestId ) called\n";
  }

  // Contrived example to show that ~Request() is called if the delegating constructor completed
  Request( Priority priority ) : 
    Request( priority, "Empty" )
  {
    throw std::exception( "This constructor is deprecated, RequestId field is now mandatory." );
  }
  ~Request()
  {
    std::cout 
      << "~Request() called:"
      << "RequestId " << m_requestId << ", "
      << "Priority " << toString( m_priority ) << "\n";
  }
private:
  std::string toString( const std::vector<int>& requestId )
  {
    std::string tmpId;
    for (auto elem : requestId)
    {
      if ( elem < 0 || 9 < elem )
        throw std::exception("Invalid request id, should be digits");
      tmpId.push_back(static_cast<char>(elem + '0'));
    }
    return tmpId;
 }

 std::string toString( Priority p )
 {
   if (p == Priority::Low ) return "Low";
   else if ( p == Priority::Medium ) return "Medium";
   else if ( p == Priority::High ) return "High";
   else
     throw std::exception( "Unexpected Priority" );
 }
 Priority m_priority;
 const std::string m_requestId;
};

And here’s a program that exercises the Request class (this uses musingstudio::initialize to conveniently initialize a standard container):

int _tmain(int argc, _TCHAR* argv[])
{
  std::cout << "\nCall fully specified constructor\n";
  Request fullySpecified( Request::Priority::High, "HeartTransplant-749553" );

  std::cout << "\nCall a delegating constructor\n";
  Request defaultPriority( "BookDelivery-5542" );

  std::cout << "\nCall chained delegating constructors\n";
  Request legacy( musingstudio::initialize<std::vector<int>>( { 1, 6 } ) );

  std::cout << "\nThis should throw without executing the destructor...\n";
  try
  {
    // This should throw due to -ve input, but does NOT execute ~Request()
    // because no constructor call completed
    Request invalid( musingstudio::initialize<std::vector<int>>( {-1} ) );
  }
  catch( const std::exception& exc )
  {
    std::cout << "ERROR: " << exc.what() << std::endl;
  }

  std::cout << "\nThis should throw and execute the destructor...\n";
  try
  {
    // This will throw because no requestId is not specified
    // (contrived example to show that ~Request() is executed
    // because the delegating constructor succeeded).
    Request noRequestId( Request::Priority::Low );
  }
  catch( const std::exception& exc )
  {
    std::cout << "ERROR: " << exc.what() << std::endl;
  }

  std::cout << "\nRemaining destructors...\n";

  return 0;
}

DelegatingConstructorsOutput
As with other Nov CTP features, Visual Studio intellisense hasn’t caught up yet, so expect to see red squiggly lines all over the code if you try this out.

What’s interesting is that it’s now possible for ~Request() to be called if a constructor fails to complete, as long as the delegatee (inner) constructor does complete.

Leave a comment

Filed under C++ Code

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.