Delegating Constructors (revision 3)



Similar documents
CORBA Programming with TAOX11. The C++11 CORBA Implementation

Object Oriented Software Design II

explicit class and default definitions revision of SC22/WG21/N1582 = and SC22/WG21/ N

C++ INTERVIEW QUESTIONS

PART-A Questions. 2. How does an enumerated statement differ from a typedef statement?

Storage Classes CS 110B - Rule Storage Classes Page 18-1 \handouts\storclas

C++ Overloading, Constructors, Assignment operator

C++FA 5.1 PRACTICE MID-TERM EXAM

KITES TECHNOLOGY COURSE MODULE (C, C++, DS)

Konzepte objektorientierter Programmierung

Course Name: ADVANCE COURSE IN SOFTWARE DEVELOPMENT (Specialization:.Net Technologies)

OpenCL Static C++ Kernel Language Extension

An Incomplete C++ Primer. University of Wyoming MA 5310

Computer Programming C++ Classes and Objects 15 th Lecture


N3458: Simple Database Integration in C++11

vector vec double # in # cl in ude <s ude tdexcept> tdexcept> // std::ou std t_of ::ou _range t_of class class V Vector { ector {

CISC 181 Project 3 Designing Classes for Bank Accounts

Multichoice Quetions 1. Atributes a. are listed in the second part of the class box b. its time is preceded by a colon. c. its default value is

CS193D Handout 06 Winter 2004 January 26, 2004 Copy Constructor and operator=

Introduction to C++ Introduction to C++ Week 7 Dr Alex Martin 2013 Slide 1

The C Programming Language course syllabus associate level

Object Oriented Software Design II

IS0020 Program Design and Software Tools Midterm, Feb 24, Instruction

Constructor, Destructor, Accessibility and Virtual Functions

Object Oriented Software Design II

13 Classes & Objects with Constructors/Destructors

Advanced Data Structures

Operator Overloading. Lecture 8. Operator Overloading. Running Example: Complex Numbers. Syntax. What can be overloaded. Syntax -- First Example

Fundamentals of Java Programming

Applied Informatics C++ Coding Style Guide

Lecture 3. Arrays. Name of array. c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] c[8] c[9] c[10] c[11] Position number of the element within array c

PROBLEM SOLVING SEVENTH EDITION WALTER SAVITCH UNIVERSITY OF CALIFORNIA, SAN DIEGO CONTRIBUTOR KENRICK MOCK UNIVERSITY OF ALASKA, ANCHORAGE PEARSON

Basics of C++ and object orientation in OpenFOAM

Glossary of Object Oriented Terms

C++FA 3.1 OPTIMIZING C++

Polymorphism. Problems with switch statement. Solution - use virtual functions (polymorphism) Polymorphism

1 bool operator==(complex a, Complex b) { 2 return a.real()==b.real() 3 && a.imag()==b.imag(); 4 } 1 bool Complex::operator==(Complex b) {

CpSc212 Goddard Notes Chapter 6. Yet More on Classes. We discuss the problems of comparing, copying, passing, outputting, and destructing

Variable Base Interface

C++ DATA STRUCTURES. Defining a Structure: Accessing Structure Members:

For the next three questions, consider the class declaration: Member function implementations put inline to save space.

CS107L Handout 02 Autumn 2007 October 5, 2007 Copy Constructor and operator=

Chapter 4 OOPS WITH C++ Sahaj Computer Solutions

Sources: On the Web: Slides will be available on:

Embedded Programming in C/C++: Lesson-1: Programming Elements and Programming in C

Class 16: Function Parameters and Polymorphism

MSP430 C/C++ CODE GENERATION TOOLS Compiler Version 3.2.X Parser Error/Warning/Remark List

1.1.3 Syntax The syntax for creating a derived class is very simple. (You will wish everything else about it were so simple though.

Chapter 5 Names, Bindings, Type Checking, and Scopes

Syntax Check of Embedded SQL in C++ with Proto

Objectif. Participant. Prérequis. Remarque. Programme. C# 3.0 Programming in the.net Framework. 1. Introduction to the.

Copyright 2001, Bill Trudell. Permission is granted to copy for the PLoP 2001 conference. All other rights reserved.

Software Engineering Concepts: Testing. Pointers & Dynamic Allocation. CS 311 Data Structures and Algorithms Lecture Slides Monday, September 14, 2009

Functional Programming in C++11

WORKSPACE WEB DEVELOPMENT & OUTSOURCING TRAINING CENTER

Programming and Software Development (PSD)

1. Polymorphism in C++...2

Ch 7-1. Object-Oriented Programming and Classes

Moving from CS 61A Scheme to CS 61B Java

CSCI 253. Object Oriented Programming (OOP) Overview. George Blankenship 1. Object Oriented Design: Java Review OOP George Blankenship.

Exception Handling for C++

C++ Programming Language

Exception Handling. Overloaded methods Interfaces Inheritance hierarchies Constructors. OOP: Exception Handling 1

Designing with Exceptions. CSE219, Computer Science III Stony Brook University

Sequences in the C++ STL

Coding conventions and C++-style

Java Interview Questions and Answers

Implementation Aspects of OO-Languages

Semantic Analysis: Types and Type Checking

A deeper look at Inline functions

Subject Name: Object Oriented Programming in C++ Subject Code:

Binary compatibility for library developers. Thiago Macieira, Qt Core Maintainer LinuxCon North America, New Orleans, Sept. 2013

Parameter Passing. Standard mechanisms. Call by value-result Call by name, result

Introduction to Object-Oriented Programming

CIS 190: C/C++ Programming. Polymorphism

How Safe does my Code Need to be? Shawn A. Prestridge, Senior Field Applications Engineer

Organization of Programming Languages CS320/520N. Lecture 05. Razvan C. Bunescu School of Electrical Engineering and Computer Science

Tutorial on C Language Programming

Compiler Construction

An Overview of Java. overview-1

1 Abstract Data Types Information Hiding

More C++ Concepts. Operator overloading Friend Function This Operator Inline Function

Inline Variables. Document Number: N4424 Date: Hal Finkel and Richard Smith

Linked Lists: Implementation Sequences in the C++ STL

CS107L Handout 04 Autumn 2007 October 19, 2007 Custom STL-Like Containers and Iterators

Note: Syntactically, a ; is needed at the end of a struct definition.

Curriculum Map. Discipline: Computer Science Course: C++

Handout 1. Introduction to Java programming language. Java primitive types and operations. Reading keyboard Input using class Scanner.

Chapter 13 - Inheritance

Object-Oriented Design Lecture 4 CSU 370 Fall 2007 (Pucella) Tuesday, Sep 18, 2007

El Dorado Union High School District Educational Services

Introduction to Distributed Computing using CORBA

C++ Crash Kurs. C++ Object-Oriented Programming

Chapter 2: Algorithm Discovery and Design. Invitation to Computer Science, C++ Version, Third Edition

The programming language C. sws1 1

6.088 Intro to C/C++ Day 4: Object-oriented programming in C++ Eunsuk Kang and Jean Yang

GENERIC and GIMPLE: A New Tree Representation for Entire Functions

Boolean Expressions, Conditions, Loops, and Enumerations. Precedence Rules (from highest to lowest priority)

Java from a C perspective. Plan

Transcription:

Doc No: SC22/WG21/N1986 J16/06 0056 Date: 2006 04 06 Project: JTC1.22.32 Reply to: Herb Sutter Francis Glassborow Microsoft Corp. Association of C & C++ Users 1 Microsoft Way 64 Southfield Road Redmond WA USA 98052 Oxford UK OX4 1PA Email: hsutter@microsoft.com Email: francis.glassborow@ntlworld.com Delegating Constructors (revision 3) Note: The only change since revision 1 was to fix two bugs in example code and refine wording based on Core WG wording review in Mont Tremblant and Berlin. 1. The Problem and Current Workarounds... 2 1.1. Overview... 2 1.2. Current Workarounds... 2 2. Proposal... 3 2.1. Basic Cases... 3 2.2. Constructor templates... 6 2.3. Constructor function try blocks... 7 3. Interactions and Implementability... 8 3.1. Interactions... 8 3.2. Implementability... 8 4. Proposed Wording... 8 5. References... 10

Delegating Constructors (revision 3) page 2 1. The Problem and Current Workarounds 1.1. Overview C++ does not provide a mechanism by which one constructor can delegate to another. This means that where it is not possible (or considered undesirable) to use default arguments, the class maintainer has to write and maintain multiple constructors. This can lead to tedious code duplication at both source and object level, which impedes maintainability (because of the potential for introducing inconsistencies) and in some cases can lead to minor code bloat. Other OO languages, such as Java, do provide this feature. As Java is often used as an introductory language, an increasing number of people learn C++ with prior experience of Java. There are substantial and desirable differences between the languages without having ones for which the only justification is historical. Today s workarounds boil down to delegating work to a common initializer function, which does not permit delegating the initialization of bases and members. This paper proposes extensions to constructors that will reduce repetitive coding which is tedious and fragile. The proposed changes are pure extensions to ISO C++ that will not affect the meaning of existing programs. We note that recent independent proposals from author Glassborow (see N1445) and C++/CLI (see [C++/CLI WD1.1]) are nearly identical in syntax and semantics. This proposal is based on both of these recent works. This proposal falls into the following categories: Improve support for library building. Make C++ easier to teach and learn, particularly in competition with languages like Java. 1.2. Current Workarounds Today, C++ books recommend code like the following that delegates to a common initialization function: class X void CommonInit(); Y y_; Z z_; X(); X( int ); X( W ); ;

Delegating Constructors (revision 3) page 3 X::X() : y_(42), z_(3.14) CommonInit(); X::X( int i ) : y_(i), z_(3.14) CommonInit(); X::X( W e ) : y_(53), z_( e ) CommonInit(); This is undesirable for the following reasons: Constructor body redundancy. In this case, one of the constructors could be replaced with a default parameter. The other can t, at least not without changing the calling semantics. Member initialization redundancy. The workaround cannot delegate the actual initialization of the member variables too, at least not without significantly restructuring the class (e.g., splitting off the data members into a second class held by pointer and allocated by CommonInit()). There is no way to achieve this effect without language support, because once we re in a nonconstructor member function it s too late, and the members have already been constructed. There is no way to really delegate everything, including the member construction. Aside: Note that novice programmers frequently (and mistakenly) think that the delegating constructor feature already exists, because code like the following compiles, although it doesn t do what they expect: class X int i_; X(); X( int ); ; X::X() DoSomethingObservableToThisObject(); X::X( int i ) : i_(i) X(); // oops! compiles, but no-op 2. Proposal 2.1. Basic Cases We propose that a constructor of a class type X (the delegating constructor ) may have an initializer list that invokes another constructor of the same type (the target constructor ). That is, the delegating constructor delegates the object s initialization to another constructor, gets control back, and then optionally performs other actions as well. A delegating constructor can also be a target constructor of some other delegating constructor. For example: class X int i_; X( int i ) : i_(i) X() : X(42) // i_ == 42 ;

Delegating Constructors (revision 3) page 4 The following rules apply: Out of line definitions are allowed as usual (see example below). At most one other constructor may be named as the target constructor. If a sibling constructor is named in the initializer list, then the initializer list shall contain nothing else (i.e., no other base or member initializers are allowed). The target constructor is selected by overload resolution and template argument deduction, as usual. Any target constructor may itself delegate to yet another constructor. If there is an infinitely recursive cycle (e.g., constructor C1 delegates to another constructor C2, and C2 also delegates to C1), the behavior is undefined. No diagnostic is required, because detecting the circularity can be burdensome to detect at compile time in the general case, when constructors are defined in different translation units. As a quality of implementation issue, implementers are encouraged to diagnose violations wherever this is feasible. Statements in the delegating constructor body are executed following the complete execution of the target constructor. Local variables in a delegated constructor body are no longer in scope in the delegating constructor body. The lifetime of an object begins when any constructor (i.e., in the case of delegation, the ultimate target constructor) is successfully completed. For the purposes of [C++03] 3.8, the constructor call has completed means any constructor call. This means that an exception thrown from the body of a delegating constructor will cause the destructor to be invoked automatically. Example: Example: class X X( int, W& ); Y y_; Z z_; X(); X( int ); X( W& ); ; X::X( int i, W& e ) : y_(i), z_(e) /*Common Init*/ X::X() : X( 42, 3.14 ) SomePostInitialization(); X::X( int i ) : X( i, 3.14 ) OtherPostInitialization(); X::X( W& w ) : X( 53, w ) /* no post-init */ X x( 21 ); // if the construction of y_ or z_ throws, X::~X is invoked class FullName string firstname_; string middlename_; string lastname_;

Delegating Constructors (revision 3) page 5 Example: FullName(string firstname, string middlename, string lastname); FullName(string firstname, string lastname); FullName(const FullName& name); ; FullName::FullName(string firstname, string middlename, string lastname) : firstname_(firstname), middlename_(middlename), lastname_(lastname) //... // delegating copy constructor FullName::FullName(const FullName& name) : FullName(name.firstName_, name.middlename_, name.lastname_) //... // delegating constructor FullName::FullName(string firstname, string lastname) : FullName(firstName, "", lastname) //... class ex ex(int =0, double = 0.0, float = 0.0, std::string = ""); ex(int, double, std::string); ex(int, std::string); private: int j; double d; float f; std::string s; ; ex::ex(int jp, double dp, float fp, std::string sp) : j(jp), d(dp), f(fp), s(sp) std::string message("full ctor"); std::cout << message <<'\'; ex::ex(int jp, double dp, std::string sp) : ex(jp, dp, 1.0, sp) std::string message("float defaulted ctor"); std::cout << message << '\';

Delegating Constructors (revision 3) page 6 ex::ex(int jp, std::string sp) : ex(jp, 0.0, sp) std::string message("float & double defaulted ctor"); std::cout << message << '\n'; In the above example, the last constructor executes as if the following had been written: ex::ex(int jp, std::string sp) : j(jp), d(0.0), f(1.0), s(sp) std::string message("full ctor"); std::cout << message <<'\'; try std::string message("float defaulted ctor"); std::cout << message << '\'; catch( ) ~ex(); throw; try std::string message("float & double defaulted ctor"); std::cout << message << '\n'; catch( ) ~ex(); throw; (Note that this rewrite is accurate for this example, but cases using constructor function try blocks have no direct rewrite; see 2.3.) Note that it can make sense to delegate to a constructor that actually takes fewer arguments. For example (contributed by Roger Orr): Consider std::fstream. The standard lists two constructors ( 27.8.1.12(1 2)): and basic_fstream() explicit basic_fstream(const char* s, ios_base::openmode mode); An implementation of the second constructor using a delegating constructor would be: basic_fstream::basic_fstream( const char* s, ios_base::openmode mode) : basic_fstream() if(open(s, mode) == 0) setstate(failbit); 2.2. Constructor templates When using constructors that are templates, deduction works as usual. For example:

Delegating Constructors (revision 3) page 7 class X template<class T> X( T, T ) : l_( first, last ) /*Common Init*/ list<int> l_; X( vector<short>& ); X( deque<char>& ); ; X::X( vector<short>& v ) : X( v.begin(), v.end() ) // T is deduced as vector<short>::iterator 2.3. Constructor function try blocks When using constructor function try blocks, the invocation of a target constructor is treated just like any other mem initializer; an exception emitted from the initializer list or body of the target constructor means that the body of the delegating constructor is never entered, and the exception can be caught by the delegating constructor s function try block if there is an appropriate handler. For example: class X X( Y&, int, double ); Y y_; int i_; X( double, Y ); X( Y ); ; X::X( Y& y, int i, double d ) try : y_( y*d ), i_(i) cout << X::X(Y&,int,double) body << endl; throw 1; catch( ) cout << X::X(Y&,int,double) catch << endl; // implicit rethrow X::X( double d, Y y ) try : X( y, 42, d ) cout << X::X(double,Y) body << endl; catch( ) cout << X::X(double,Y) catch << endl; // implicit rethrow X::X( Y y ) try : X( 3.14, y ) cout << X::X(Y) body << endl; catch( ) cout << X::X(Y) catch << endl; // implicit rethrow int main() X x( Y() ); // Output X::X(Y&,int,double) body X::X(Y&,int,double) catch X::X(double,Y) catch X::X(Y) catch In the above example, the last constructor executes as if the following had been written (this is pseudocode, not legal C++:

Delegating Constructors (revision 3) page 8 X::X( Y y ) try try try : y_( y*3.14 ), i_(42) cout << X::X(Y&,int,double) body << endl; throw 1; catch( ) cout << X::X(Y&,int,double) catch << endl; throw; cout << X::X(double,Y) body << endl; catch( ) cout << X::X(double,Y) catch << endl; throw; cout << X::X(Y) body << endl; catch( ) cout << X::X(Y) catch << endl; throw; 3. Interactions and Implementability 3.1. Interactions The proposed feature fits well with the rest of the language, naturally extending initializer list syntax and semantics. For template interactions, see above. There is no impact on code that uses the constructor; the delegation is an implementation detail. By design, there are no effects on existing code. 3.2. Implementability There are no known or anticipated difficulties in implementing this feature. 4. Proposed Wording In this section, where changes are either specified by presenting changes to existing wording, strikethrough text refers to existing text that is to be deleted, and underscored text refers to new text that is to be added. No change to the grammar is needed.

Delegating Constructors (revision 3) page 9 4.1. Changes to 3.8 Change 3.8(1) as follows: 1 The lifetime of an object is a runtime property of the object. The lifetime of an object of type T begins when: storage with the proper alignment and size for type T is obtained, and if T is a class type and the constructor invoked to create the object is non trivial (12.1), the principal constructor call (12.6.2) has completed. [ Note: the initialization can be performed by a constructor call or, in the case of an aggregate with an implicitlydeclared non trivial default constructor, an aggregate initialization 8.5.1. end note ] The lifetime of an object of type T ends when: if T is a class type with a non trivial destructor (12.4), the destructor call starts, or the storage which the object occupies is reused or released. 4.2. Changes to 12.6.2 Change 12.6.2(2) as follows: 2 Names in a mem initializer id are looked up in the scope of the constructor s class and, if not found in that scope, are looked up in the scope containing the constructor s definition. [ Note: if the constructor s class contains a member with the same name as a direct or virtual base class of the class, a mem initializer id naming the member or base class and composed of a single identifier refers to the class member. A mem initializer id for the hidden base class may be specified using a qualified name. end note ] Unless the mem initializer id names a non static data member of the constructor s class, the constructor s class, or a direct or virtual base of that class, the mem initializer is ill formed. A mem initializer list can initialize a base class using any name that denotes that base class type. [ Example: struct A A(); ; typedef A global_a; struct B ; struct C: public A, public B C(); ; C::C(): global_a() // mem initializer for base A end example] A mem initializer list can delegate to another constructor (the target constructor) of the constructor s class using any name that denotes the constructor s class itself. If a meminitializer id designates the constructor s class, it shall be the only mem initializer; the constructor is a delegating constructor, and the constructor selected by the mem initializer is the target constructor. The principal constructor is the first constructor invoked in the construction of an object (that is, not a target constructor for that object s construction). The target constructor is selected by overload resolution. Once the target constructor returns, the body of the delegating

Delegating Constructors (revision 3) page 10 constructor is executed. If a constructor delegates to itself directly or indirectly, the program is ill formed; no diagnostic is required. [Example: struct C C( int ) // 1: non delegating constructor C() : C( 42 ) // 2: delegates to 1 C( char c ) : C( 42.0 ) // 3: ill formed due to recursion with 4 C( double d ) : C( a ) // 4: ill formed due to recursion with 3 ; end example] If a mem initializer id is ambiguous because it designates both a direct nonvirtual base class and an inherited virtual base class, the mem initializer is ill formed. [Example: struct A A(); ; struct B: public virtual A ; struct C: public A, public B C(); ; C::C(): A() // ill formed: which A? end example] A ctor initializer may initialize the member of an anonymous union that is a member of the constructor s class. If a ctor initializer specifies more than one mem initializer for the same member, for the same base class or for multiple members of the same union (including members of anonymous unions), the ctor initializer is ill formed. 4.3. Changes to 15 Change 15.2(2) as follows: 2 An object that is partially constructed or partially destroyed will have destructors executed for all of its fully constructed subobjects, that is, for subobjects for which the principal constructor (12.6.2) has completed execution and the destructor has not yet begun execution. Similarly, if the non delegating constructor for an object has completed execution and a delegating constructor for that object exits with an exception, the object s destructor will be invoked. Should a constructor for an element of an automatic array throw an exception, only the constructed elements of that array will be destroyed. If the object or array was allocated in a new expression, the matching deallocation function (3.7.3.2, 5.3.4, 12.5), if any, is called to free the storage occupied by the object. Change 15.3(11) as follows: 11 The fully constructed base classes and members of an object shall be destroyed before entering the handler of a function try block of a constructor or destructor for that object. Similarly, if a delegating constructor for an object exits with an exception after the non delegating constructor for that object has completed execution, the object s destructor shall be executed before entering the handler of a function try block of a constructor for that object.

Delegating Constructors (revision 3) page 11 5. References [C++03] [C++/CLI WD1.1] Programming Language C++ (ISO/IEC 14882:2003(E)). C++/CLI Language Specification, Working Draft 1.1, Jan. 2004 (Ecma/TC39 TG5/2004/3).