- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
-
Tips and Techniques
- Using the Swap() Algorithm
- Using class stopwatch for Performance Measurements
- Extending <tt><iostream></tt> to Support User-Defined Types
- Using <tt>auto_ptr</tt> To Automate Memory Management
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part II
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part III
- Using <tt>enum</tt>s as Mnemonic Indexes
- Create Objects on Pre-Allocated Memory Using <tt>Placement-new</tt>
- Online Books: <tt>Placement-new</tt>
- Bitwise Operators
- Bitwise Operators II
- Who's <tt>this</tt>?
- A Reference Guide
- The Virtues of Multiple Inheritance
- Interfaces
- Multiple Inheritance: Construction and Destruction Order
- nothrow new
- POD Initialization
- Object Initialization
- <tt>const</tt> Declarations
- The Semantics of <tt>volatile</tt>
- <tt>inline</tt> Functions
- Project Organization Guidelines
- All About <tt>bool</tt>
- <tt>typedef</tt> Declarations
- State of the <tt>union</tt>
- Dynamic Cast Uses
- Integrating C and C++
- <tt>const</tt>-Correctness
- <tt>const</tt>-Correctness: Advanced Issues
- Sprucing Up Legacy Code
- Virtual Constructors
- Naming Names
- Function Calls
- Speaking Standardese (updated)
- Speaking Standardese: the One Definition Rule
- Declarations and Definitions
- More on Declarations and Definitions
- The Most Vexing Parse
- Finally, At Last
- Sound Bytes (Admittedly Off Topic)
- Local Classes
- Complex Arithmetic
- Floating Point Woes
- String Manipulation
- The Object Model
- The Object Model II
- The Object Model III
- Temporary Objects
- Temporary Objects: Advanced Techniques
- Over-Engineering
- Security Enhancements
- Drop the (automatic) Pilot
- Choosing the Right Container
- Choosing the Right Container II
- Choosing the Right Container, Part III
- Arrays and Pointers
- Low-Level File I/O
- Low-Level File I/O Part II
- static Declarations, Part I
- static Declarations, Part II
- <code>static</code> Initialization Order
- Revisiting the Deprecation of File-Scope Static
- Virtual Memory and Memory Mapping
- Cellular Phone Programming Guidelines
- The Handle/Body Idiom
- Whole Program Optimization, Part I
- Whole Program Optimization, Part II
- Manipulating Directories
- Window Dressing
- <code>friend</code> Declarations
- <code>friend</code> Part II: the Interaction of Friendship and Template Classes
- Forcing Object Allocation on Specific Storage Types
- Lazy Evaluation
- Cache and Carry
- Controlling a Container’s Capacity
- Non-Blocking I/O, Part I
- Non-Blocking I/O, Part II
- Using Unions for Automatic Conversion
- Launching a Child Process
- <tt>switch</tt> Statements
- Introducing the "struct Hack"
- Scoped Enumerators
- Doing Statistics with STL
- Fixing the "Unresolved External" Linkage Error
- Understanding Calling Conventions
- Understanding the Empty Base Optimization
- Implementing RPC with the door Library, Part 1
- Implementing RPC with the door Library, Part 2
- Eliminating Two Common Pointer and <tt>sizeof</tt> Bugs
- Command Line Arguments
- Performance Myths Busting
- Tag Names And Types Part I
- Tag Names And Types Part II
- The Infamous goto
- Trimming Strings
- Can Objects Live Forever? Part I
- Can Objects Live Forever? Part II
- Five Ways to Improve Your Functions
- Member Aggregate Initialization
- Five Futile Coding-Style Debates
- The Good Parasite Idiom: An Exercise in OOD
- The Good Parasite Idiom: An Exercise in OOD, Part II
- The Good Parasite Idiom: An Exercise in OOD, Part III
- Ten Techniques to Reduce the Size of Your Classes, Part I
- Ten Techniques to Reduce the Size of Your Classes, Part II: Inheritance Issues
- Ten Techniques to Reduce the Size of Your Classes, Part III
- Ten Techniques to Reduce the Size of Your Classes IV
- Taking the Address of an Object with an Overloaded Operator <tt>&</tt>
- strcpy() -- How and Why Does It "Just Work"?
- Anonymous Structs
- Five Easy Ways to Reduce The Size of your Executables
- Standard Layout Classes and Trivially Copyable Types, Part I
- Standard Layout Classes and Trivially Copyable Types, Part II
- Five Simple Code Sanity Checks
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
Speaking Standardese: the One Definition Rule
Last updated Jan 1, 2003.
The One Definition Rule (ODR), as the name suggests, requires that an object with external linkage, a non-inline function, a class, an enumeration or a template shall have exactly one definition in the program.
Rationale
There can be more than one definition in the program of a class type, enumeration type, inline function with external linkage, class template, non-static function template, static data member of a class template, member function template, or template specialization for which some template parameters are not specified provided that:
- Each definition appears in a different translation unit
- All definition referring to the same entity must be identical
In other words, a program may consist of multiple translation units, each of which containing the same definition of a certain entity (class template, enum, class, inline function etc.) Later, at linkage time, these multiple definitions are collapsed into a single definition. Obviously, the separately-compiled definitions of the same entity must be identical but what exactly does "identical definition" mean? An entity D that is defined in more than one translation unit satisfies the ODR if it meets the criteria listed below.
Token-by-Token Identity
Each definition of D must consist of the same sequence of tokens. For example, the following definitions of class S have the same sequence of tokens although they look different to the human eye:
//translation unit 1
class S {};
//translation unit 2
#define X
class S{
X
};
Function Call Resolution
In each definition of D, overloaded operators referred to, implicit calls to conversion functions, constructors, operator new and operator delete functions shall refer to the same function, or to a function defined within the definition of D (i.e., an inline function). Consider:
//translation unit 1
class S
{
public:
S(int);
~S(){cout<<"goodbye!"<<endl;}
};
//translation unit 2
class S{
public:
S(int);
~S(){cout<<"goodbye!"<<endl;}
};
The two definitions of S are identical.
Default Arguments Identity
In each definition of D, a default argument used by a function call is treated as if its token sequence were present in the definition of D. In other words, default arguments are subjected to the previous two requirements. Consider:
//translation unit 1
const int ZERO=0;
class S
{
public:
S(int n=ZERO);
~S(){cout<<"goodbye!"<<endl;}
};
//translation unit 2
class S{
public:
S(int n=0) {}
~S(){cout<<"goodbye!"<<endl;}
};
Both definitions of S are identical.
Implicitly-Defined Constructor Identity
A class D that has an implicitly defined constructor is treated as if its constructor is defined in every translation unit. The implicitly defined constructor must call the same constructor(s) of D’s base class(es) and member objects. Consider:
// translation unit 1
struct A {
A(int);
A(int, int);
};
A::A(int = 0) {}
class D: public A {};
D d; // implicitly-defined D() calls A(int)
// translation unit 2
struct A {
A(int);
A(int, int);
};
A::A(int = 0, int = 0) {}
class D: public A { }; // // implicitly-defined D() calls A(int, int)
Are the two definitions of D identical? Each definition of D has an implicitly-defined default constructor that invokes a default constructor of the base class A. In order to qualify as identical, the implicitly-defined constructors of D must call the same constructor of A in both translation units. This requirement isn’t met. In translation unit 1, D’s default constructor invokes the default constructor A(int), whereas in translation unit 2, it invokes A(int, int). Hence, the two definitions of D violate the ODR.
Template Identity
If D is a template that is defined in more than one translation unit, then the four requirements above shall apply to names from D’s enclosing scope used in the template definition (i.e., to independent names), and also to dependent names at the point of instantiation.
ODR Violations
If the definitions of D satisfy all the requirements above, then the program shall behave as if there were a single definition of D. Technically speaking, either the linker will discard all copies but one, or there will be multiple definitions of D in the program, but the program will behave as if there were only one definition of D.
If the definitions of D do not satisfy these requirements, then the behavior is undefined. Usually, compilers can’t detect ODR violations (unless you’re using a tool that analyzes the entire program). Therefore, no diagnostic is required in ODR violation cases.
