Ru-Brd
Page 1 of 182
Table of Contents
: Addison Wesley
: May 03, 1996
: 0-201-83454-5
: 304
•
Inside the C++ Object Model
By Stanley B. Lippman
Publisher
Pub Date
ISBN
Pages
Inside the C++ Object Model focuses on the underlying mechanisms that support object-oriented
programming within C++: constructor semantics, temporary generation, support for encapsulation,
inheritance, and "the virtuals"-virtual functions and virtual inheritance. This book shows how your
understanding the underlying implementation models can help you code more efficiently and with greater
confidence. Lippman dispells the misinformation and myths about the overhead and complexity associated
with C++, while pointing out areas in which costs and trade offs, sometimes hidden, do exist. He then
explains how the various implementation models arose, points out areas in which they are likely to evolve,
and why they are what they are. He covers the semantic implications of the C++ object model and how that
model affects your programs.
Highlights
Explores the program behavior implicit in the C++ Object Model's support of object-oriented
programming.
Explains the basic implementation of the object-oriented features and the trade offs implicit in those
features.
Examines the impact on performance in terms of program transformation.
Provides abundant program examples, diagrams, and performance measurements to relate object-
oriented concepts to the underlying object model.
If you are a C++ programmer who desires a fuller understanding of what is going on "under the hood," then
Inside the C++ Object Model is for you!
Ru-Brd
Ru-Brd
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 2 of 182
: Addison Wesley
: May 03, 1996
: 0-201-83454-5
: 304
Copyright
Preface
Table of Contents
•
Inside the C++ Object Model
By Stanley B. Lippman
Publisher
Pub Date
ISBN
Pages
Chapter 4. The Semantics of Function
Chapter 3. The Semantics of Data
Chapter 1. Object Lessons
Layout Costs for Adding Encapsulation
Section 1.1. The C++ Object Model
Section 1.2. A Keyword Distinction
Section 1.3. An Object Distinction
What Is the C++ Object Model?
Organization of This Book
The Intended Audience
A Note on Program Examples and Program Execution
Acknowledgments
References
Chapter 2. The Semantics of Constructors
Section 2.1. Default Constructor Construction
Section 2.2. Copy Constructor Construction
Section 2.3. Program Transformation Semantics
Section 2.4. Member Initialization List
Section 3.1. The Binding of a Data Member
Section 3.2. Data Member Layout
Section 3.3. Access of a Data Member
Section 3.4. Inheritance and the Data Member
Section 3.5. Object Member Efficiency
Section 3.6. Pointer to Data Members
Section 4.1. Varieties of Member Invocation
Section 4.2. Virtual Member Functions
Section 4.3. Function Efficiency
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Section 4.4. Pointer-to-Member Functions
Section 4.5. Inline Functions
Chapter 5. Semantics of Construction, Destruction, and Copy
Presence of a Pure Virtual Destructor
Presence of a Virtual Specification
Presence of const within a Virtual Specification
A Reconsidered Class Declaration
Section 5.1. Object Construction without Inheritance
Section 5.2. Object Construction under Inheritance
Section 5.3. Object Copy Semantics
Section 5.4. Object Efficiency
Section 5.5. Semantics of Destruction
Ru-Brd
Ru-Brd
Copyright
Chapter 6. Runtime Semantics
Section 6.1. Object Construction and Destruction
Section 6.2. Operators new and delete
Section 6.3. Temporary Objects
Chapter 7. On the Cusp of the Object Model
Section 7.1. Templates
Section 7.2. Exception Handling
Section 7.3. Runtime Type Identification
Section 7.4. Efficient, but Inflexible?
Page 3 of 182
The frontispiece art is an engraving Knight, Death and the Devil by Albrecht Dürer, 1471–1528. Courtesy,
Museum of Fine Arts, Boston, Massachusetts. Gift of Mrs. Horatio Greenough Curtis in Memory of her
Husband, Horatio Greenough Curtis.
The photograph on the back cover is by David Remba.
Extracts on pages 100–112 are from the Journal of C Language Translation, Vol. 6, No. 2, December 1994.
Copyright 1995, I.E.C.C. Editor/publisher John R. Levine, Trumansburg, New York. Reprinted by permission of
the publisher.
Senior Editor: Tom Stone
Associate Editor: Debbie Lafferty
Associate Production Supervisor: Patricia A. Oduor
Copyeditor: Diane Freed
Proofreader: Bunny Ames
Art Editing Supervisor: Meredith Nightingale
Senior Manufacturing Coordinator: Judith Y. Sullivan
Library of Congress Cataloging-in-Publication Data
Lippman, Stanley B.
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 4 of 182
Inside the C++ object model / by Stanley Lippman.
p. cm
Includes bibliographical references and index.
1. C++ (Computer program language) 2. Object-oriented programming (Computer science) I. Title. II. Title:
C plus plus object models
ZA76.73.C153L58 1996
005.13'3 – – dc20 96–6024
CIP
The programs and applications presented in this book have been included for their instructional value only.
Access the latest information about Addison-Wesley books from our World Wide Web page:
http://www.aw.com/cseng/
Copyright ©1996 by Addison-Wesley Publishing Company, Inc. All rights reserved. No part of this publication
may be reproduced, stored in a retrieval system, or transmitted, in any form or by any means, electronic,
mechanical, photocopying, recording, or otherwise, without the prior written permission of the publisher.
Printed in the United States of America.
1 2 3 4 5 6 7 8 9 10-MA-0099989796
Dedication
for Beth
who suffered with forbearance
the widowhood of an author's wife
and nonetheless provided wildly unreasonable support
for Danny & Anna
who suffered with far less forbearance
but no less love
Ru-Brd
Ru-Brd
Preface
For nearly a decade within Bell Laboratories, I labored at implementing C++. First it was on cfront, Bjarne
Stroustrup's original C++ implementation (from Release 1.1 back in 1986 through Release 3.0, made
available in September 1991). Then it was on what became known internally as the Simplifier, the C++
Object Model component of the Foundation project. It was during the Simplifier's design period that I
conceived of and began working on this book.
What was the Foundation project? Under Bjarne's leadership, a small group of us within Bell Laboratories was
exploring solutions to the problems of large-scale programming using C++. The Foundation was an effort to
define a new development model for the construction of large systems (again, using C++ only; we weren't
providing a multilingual solution). It was an exciting project, both for the work we were doing and for the
people doing the work: Bjarne, Andy Koenig, Rob Murray, Martin Carroll, Judy Ward, Steve Buroff, Peter Juhl,
and myself. Barbara Moo was supervising the gang of us other than Bjarne and Andy. Barbara used to say
that managing a software group was like herding a pride of cats.
We thought of the Foundation as a kernel upon which others would layer an actual development environment
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 5 of 182
for users, tailoring it to a UNIX or Smalltalk model as desired. Internally, we called it Grail, as in the quest
for, etc. (It seems a Bell Laboratories tradition to mock one's most serious intentions.)
Grail provided for a persistent, semantic-based representation of the program using an object-oriented
hierarchy Rob Murray developed and named ALF. Within Grail, the traditional compiler was factored into
separate executables. The parser built up the ALF representation. Each of the other components (type
checking, simplification, and code generation) and any tools, such as a browser, operated on (and possibly
augmented) a centrally stored ALF representation of the program. The Simplifier is the part of the compiler
between type checking and code generation. (Bjarne came up with the name Simplifier; it is a phase of the
original cfront implementation.)
What does a Simplifier do between type checking and code generation? It transforms the internal program
representation. There are three general flavors of transformations required by any object model component:
1.
Implementation-dependent transformations. These are implementation-specific aspects and vary
across compilers. Under ALF, they involved the transformations of what we called "tentative" nodes.
For example, when the parser sees the expression
fct();
it doesn't know if this is (a) an invocation of a function represented or pointed to by fct or (b) the
application of an overloaded call operator on a class object fct. By default, the expression is
represented as a function call. The Simplifier rewrites and replaces the call subtree when case (b)
applies.
2. Language semantics transformations. These include constructor/destructor synthesis and
augmentation, memberwise initialization and memberwise copy support, and the insertion within
program code of conversion operators, temporaries, and constructor/destructor calls.
3. Code and object model transformations. These include support for virtual functions, virtual base
classes and inheritance in general, operators new and delete, arrays of class objects, local static class
instances, and the static initialization of global objects with nonconstant expressions. An
implementation goal I aimed for in the Simplifier was to provide an Object Model hierarchy in which
the object implementation was a virtual interface supporting multiple object models.
These last two categories of transformations form the basis of this book. Does this mean this book is written
for compiler writers? No, absolutely not. It is written by a (former) compiler writer (that's me) for
intermediate to advanced C++ programmers (ideally, that's you). The assumption behind this book is that
the programmer, by understanding the underlying C++ Object Model, can write programs that are both less
error prone and more efficient.
Ru-Brd
Ru-Brd
What Is the C++ Object Model?
There are two aspects to the C++ Object Model:
1. The direct support for object-oriented programming provided within the language
2. The underlying mechanisms by which this support is implemented
The language level support is pretty well covered in my C++ Primer and in other books on C++. The second
aspect is barely touched on in any current text, with the exception of brief discussions within [ELLIS90] and
[STROUP94]. It is this second aspect of the C++ Object Model that is the primary focus of this book. (In that
sense, I consider this text to form a book-end to my C++ Primer, much as my MFA and MS degrees provide a
"fearful symmetry" to my education.) The language covered within the text is the draft Standard C++ as of
the winter 1995 meeting of the committee. (Except for some minor details, this should reflect the final form
of the language.)
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 6 of 182
The first aspect of the C++ Object Model is invariant. For example, under C++ the complete set of virtual
functions available to a class is fixed at compile time; the programmer cannot add to or replace a member of
that set dynamically at runtime. This allows for extremely fast dispatch of a virtual invocation, although at
the cost of runtime flexibility.
The underlying mechanisms by which to implement the Object Model are not prescribed by the language,
although the semantics of the Object Model itself make some implementations more natural than others.
Virtual function calls, for example, are generally resolved through an indexing into a table holding the address
of the virtual functions. Must such a virtual table be used? No. An implementation is free to introduce an
alternative mechanism. Moreover, if a virtual table is used, its layout, method of access, time of creation, and
the other hundred details that must be decided, are all decisions left to each implementation. Having said
that, however, I must also say that the general pattern of virtual function implementation across all current
compilation systems is to use a class-specific virtual table of a fixed size that is constructed prior to program
execution.
If the underlying mechanisms by which the C++ Object Model is implemented are not standardized, then one
might ask, why bother to discuss them at all? The primary reason is because my experience has shown that if
a programmer understands the underlying implementation model, the programmer can code more efficiently
and with greater confidence. Determining when to provide a copy constructor, and when not, is not
something one should guess at or have adjudicated by some language guru. It should come from an
understanding of the Object Model.
A second reason for writing this book is to dispel the various misunderstandings surrounding C++ and its
support of object-oriented programming. For example, here is an excerpt from a letter I received from
someone wishing to introduce C++ into his programming environment:
I work with a couple of individuals who have not written and/or are completely unfamiliar with
C++ and OO. One of the engineers who has been writing C code since 1985 feels very strongly
that C++ is good only for user-type applications, but not server applications. What he is saying
is to have a fast and efficient database level engine that it must be written in C compared to
C++. He has identified that C++ is bulky and slow.
C++, of course, is not inherently bulky and slow, although I've found this to be a common assumption among
many C programmers. However, just saying that is not very convincing, particularly if the person saying it is
perceived as a C++ partisan. This book is partially an attempt to lay out as precisely as I can the kinds of
overhead that are and are not inherent in the various Object facilities such as inheritance, virtual functions,
and pointers to class members.
Rather than answering the individual myself, I forwarded his letter to Steve Vinoski of Hewlett-Packard, with
whom I had previously corresponded regarding the efficiency of C++. Here is an excerpt from his response:
I have heard a number of people over the years voice opinions similar to those of your
colleagues. In every case, those opinions could be attributed to a lack of factual knowledge
about the C++ language. Just last week I was chatting with an acquaintance who happens to
work for an IC testing manufacturer, and he said they don't use C++ because "it does things
behind your back." When I pressed him, he said that he understood that C++ calls malloc()
and free() without the programmer knowing it. This is of course not true. It is this sort of
"myth and legend" that leads to opinions such as those held by your colleagues….
Finding the right balance [between abstraction and pragmatism] requires knowledge,
experience, and above all, thought. Using C++ well requires effort, but in my experience the
returns on the invested effort can be quite high.
I like to think of this book, then, as my answer to this individual, and, I hope, a repository of knowledge to
help put to rest many of the myths and legends surrounding C++.
If the underlying mechanisms supporting the C++ Object Model vary both across implementations and over
time, how can I possibly provide a general discussion of interest to any particular individual? Static
initialization provides an interesting case in point.
Given a class X with a constructor, such as the following:
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 7 of 182
class X
{
friend istream&
operator>>( istream&, X& );
public:
X( int sz = 1024 ) { ptr = new char[ sz ]; }
...
private:
char *ptr;
};
and the declaration of a global object of class X, such as the following:
X buf;
main()
{
// buf must be constructed at this point
cin >> setw( 1024 ) >> buf;
...
}
the C++ Object Model guarantees that the X constructor is applied to buf prior to the first user statement of
main(). It does not, however, prescribe how that is to get done. The solution is called static initialization;
the actual implementation depends on the degree of support provided by the environment.
The original cfront implementation not only presumed no environment support. It also presumed no explicit
platform target. The only presumption was that of being under some variant of UNIX. Our solution, therefore,
was specific only to UNIX: the presence of the nm command. The CC command (a UNIX shell script for
portability) generated an executable, ran the nm command on the executable—thereby generating a new .c
file—compiled the .c file, and then relinked the executable. (This was called the munch solution.) This did the
job by trading compile-time efficiency for portability. Eventually, however, users chaffed under the compile-
time overhead.
The next step was to provide a platform-specific solution: a COFF-based program (referred to as the patch
solution) that directly examined and threaded the program executable, thus doing away with the need to run
nm, compile, and relink. (COFF was the Common Object File Format for System V pre-Release 4 UNIX
systems.) Both of these solutions are program-based, that is, within each .c file requiring static initialization
cfront generated an sti function to perform the required initializations. Both munch and patch solutions
searched for functions bearing an sti prefix and arranged for them to be executed in some undefined order
by a _main() library function inserted as the first statement of main().
In parallel with these releases of cfront, a System V COFF-specific C++ compiler was under development.
Targeted for a specific platform and operating system, this compiler was able to effect a change in the
System V link editor: a new initialize section that provided for the collection of objects needing static
initialization. This extension of the link editor provides what I call an environment-based solution that is
certainly superior to a program-based solution.
So any generalization based on the cfront program-based solution would be misleading. Why? Because as
C++ has become a mainstream language, it has received more and more support for environment-based
solutions. How is this book to maintain a balance, then? The book's strategy is as follows: If significantly
different implementation models exist across C++ compilers, I present a discussion of at least two models. If
subsequent implementation models evolved as an attempt to solve perceived problems with the original
cfront model, as, for example, with support for virtual inheritance, I present a discussion of the historical
evolution. Whenever I speak of the traditional implementation model, I mean, of course, Stroustrup's original
design as reflected in cfront and which has provided a pattern of implementation that can still be seen today
in all commercial implementations, even if only as a "reaction against."
Ru-Brd
Ru-Brd
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003
Page 8 of 182
Organization of This Book
Chapter 1, Object Lessons, provides background on the object-based and object-oriented programming
paradigms supported by C++. It includes a brief tour of the Object Model, illustrating the current prevailing
industry implementation without looking too closely at multiple or virtual inheritance. (This is fleshed out in
Chapters 3 and 4.)
Chapter 2, The Semantics of Constructors, discusses in detail how constructors work. It discusses when
constructors are synthesized by the compiler and what that means in practical terms for your program's
performance.
Chapters 3 through 5 contain the primary material of the book. There, the details of the C++ Object Model
are discussed. Chapter 3, The Semantics of Data, looks at the handling of data members. Chapter 4, The
Semantics of Function, focuses on the varieties of member functions, with a detailed look at virtual function
support. Chapter 5, Semantics of Construction, Destruction, and Copy, deals with support of the class model
and object lifetime. Program test data is discussed within each of these chapters, where our performance
expectations are compared against actual performance as the representations move from an object-based to
object-oriented solution.
Chapter 6, Runtime Semantics, looks at some of the Object Model behavior at runtime, including the life and
death of temporary objects and the support of operators new and delete.
Chapter 7, On the Cusp of the Object Model, focuses on exception handling, template support, and runtime
type identification.
Ru-Brd
Ru-Brd
The Intended Audience
This book is primarily a tutorial, although it is aimed at the intermediate C++ programmer rather than the
novice. I have attempted to provide sufficient context to make it understandable to anyone who has had
some prior exposure to C++—for example, someone who has read my C++ Primer—and some experience in
C++ programming. The ideal reader, however, has been programming in C++ for a few years and wants to
better understand what is actually going on "under the hood." Portions of the material should be of interest
even to the advanced C++ programmer, such as the generation of temporaries and the details of the named
return value optimization. At least, this has proved to be so in the various public presentations of this
material I have given as it has evolved.
Ru-Brd
Ru-Brd
A Note on Program Examples and Program Execution
The use of program code in this text serves two primary purposes:
1. To provide concrete illustrations of the various aspects of the C++ Object Model under discussion
2. To provide test cases by which to measure the relative cost of various language features
In neither case is the code intended to represent models of production-quality programming. I am not, for
example, suggesting that a real 3D graphics library represents a 3D point using a virtual inheritance
hierarchy (although one can be found in [POKOR94]).
All the test programs in the text were compiled and executed on an SGI Indigo2xL running version 5.2 of
SGI's UNIX operating system under both its CC and NCC compilers. CC is cfront Release 3.0.1 (it generates C
code, which a C compiler then recompiles into an executable). NCC is version 2.19 of the Edison Design
Group's C++ front-end with a code generator supplied by SGI. The times were measured as the average user
time reported by the UNIX timex command and represent 10 million iterations of the test function or
statement block.
file://C:\Documents%20and%20Settings\Mark\Local%20Setting...
22/08/2003