One Definition Rule

Last updated

The One Definition Rule (ODR) is an important rule of the C++ programming language that prescribes that classes/structs and non-inline functions cannot have more than one definition in the entire program and template and types cannot have more than one definition by translation unit. It is defined in the ISO C++ Standard (ISO/IEC 14882) 2003, at section 3.2. Some other programming languages have similar but differently defined rules towards the same objective.

Contents

Summary

In short, the ODR states that:

  1. In any translation unit, a template, type, function, or object can have no more than one definition. Some of these can have any number of declarations. A definition provides an instance.
  2. In the entire program, an object or non-inline function cannot have more than one definition; if an object or function is used, it must have exactly one definition. You can declare an object or function that is never used, in which case you don't have to provide a definition. In no event can there be more than one definition.
  3. Some things, like types, templates, and extern inline functions, can be defined in more than one translation unit. For a given entity, each definition must have the same sequence of tokens. Non-extern objects and functions in different translation units are different entities, even if their names and types are the same.

Some violations of the ODR must be diagnosed by the compiler. Other violations, particularly those that span translation units, are not required to be diagnosed. [1]

Examples

In general, a translation unit shall contain no more than one definition of any class type. In this example, two definitions of the class type C occur in the same translation unit. This typically occurs if a header file is included twice by the same source file without appropriate header guards.

classC{};// first definition of CclassC{};// error, second definition of C

In the following, forming a pointer to S or defining a function taking a reference to S are examples of legal constructs, because they do not require the type of S to be complete. Therefore, a definition is not required. [2]

Defining an object of type S, a function taking an argument of type S, or using S in a sizeof expression are examples of contexts where S must be complete, and therefore require a definition. [2]

structS;// declaration of SS*p;// ok, no definition requiredvoidf(S&);// ok, no definition requiredvoidf(S*);// ok, no definition required Sf();// ok, no definition required - this is a function declaration only!Ss;// error, definition requiredsizeof(S);// error, definition required

More than one definition

In certain cases, there can be more than one definition of a type or a template. A program consisting of multiple header files and source files will typically have more than one definition of a type, but not more than one definition per translation unit.

If a program contains more than one definition of a type, then each definition must be equivalent. [3]

Definitions of static const data members

In pre-standard C++, all static data members required a definition outside of their class. However, during the C++ standardization process it was decided to lift this requirement for static const integral members. The intent was to allow uses such as:

structC{staticconstintN=10;};chardata[C::N];// N "used" without out-of-class definition

without a namespace scope definition for N.

Nevertheless, the wording of the 1998 C++ standard still required a definition if the member was used in the program. [4] This included the member appearing anywhere except as the operand to sizeof or typeid, effectively making the above ill-formed. [5]

This was identified as a defect, and the wording was adjusted to allow such a member to appear anywhere a constant expression is required, without requiring an out-of-class definition. This includes array bounds, case expressions, static member initializers, and nontype template arguments. [6]

structC{staticconstintN=10;staticconstintU=N;// Legal per C++03};chardata[C::N];// Legal per C++03template<int>structD;template<>structD<C::N>{};// Legal per C++03

However, using a static const integral member anywhere except where an integral constant-expression is required, requires a definition: [7]

structC{staticconstintN=10;};intmain(){inti=C::N;// Ill-formed in C++03. Definition of C::N required.}

This requirement was relaxed in a later standard, C++11. [7]

Example showing unexpected side effects

We need 4 files: "odr.h", "main.cpp", "odr1.cpp", "odr2.cpp"

The acronym "odr" here is short for "One Definition Rule".

odr.h:

// abstract base classclassCBase{public:virtualvoidxxx()=0;virtual~CBase()=default;};externCBase*odr1_create();externCBase*odr2_create();

main.cpp

#include"odr.h"intmain(intargc,char**argv){CBase*o1=odr1_create();CBase*o2=odr2_create();o1->xxx();o2->xxx();}

odr1.cpp

#include<stdio.h>#include"odr.h"classCDummy:publicCBase{public:voidxxx()override{printf("odr ONE dummy: Hello\n");}};CBase*odr1_create(){returnnewCDummy();}

odr2.cpp

#include<stdio.h>#include"odr.h"classCDummy:publicCBase{public:voidxxx()override{printf("odr TWO dummy: World\n");}};CBase*odr2_create(){returnnewCDummy();}

Under a Linux shell to try out, compile with:

g++ -c odr1.cpp g++ -c odr2.cpp g++ -c main.cpp g++ -o odr main.o odr1.o odr2.o 

Under a Windows Visual Studio "Build Tools Command Prompt", compile with:

cl /c main.cpp cl /c odr1.cpp cl /c odr2.cpp cl /Feodr.exe main.obj odr1.obj odr2.obj 

When executed the expected output is:

odr ONE dummy: Hello odr TWO dummy: World 

But you very likely get:

odr ONE dummy: Hello odr ONE dummy: Hello 

The problem is, that the C++ linker has to figure out how to build the virtual method table for the (two different) "CDummy" classes, and that only works if the class names are different.

See also

Related Research Articles

<span class="mw-page-title-main">C++</span> General-purpose programming language

C++ is a high-level, general-purpose programming language created by Danish computer scientist Bjarne Stroustrup. First released in 1985 as an extension of the C programming language, it has since expanded significantly over time; modern C++ currently has object-oriented, generic, and functional features, in addition to facilities for low-level memory manipulation. It is almost always implemented as a compiled language, and many vendors provide C++ compilers, including the Free Software Foundation, LLVM, Microsoft, Intel, Embarcadero, Oracle, and IBM.

In the C and C++ programming languages, an inline function is one qualified with the keyword inline; this serves two purposes:

  1. It serves as a compiler directive that suggests that the compiler substitute the body of the function inline by performing inline expansion, i.e. by inserting the function code at the address of each function call, thereby saving the overhead of a function call. In this respect it is analogous to the register storage class specifier, which similarly provides an optimization hint.
  2. The second purpose of inline is to change linkage behavior; the details of this are complicated. This is necessary due to the C/C++ separate compilation + linkage model, specifically because the definition (body) of the function must be duplicated in all translation units where it is used, to allow inlining during compiling, which, if the function has external linkage, causes a collision during linking. C and C++ resolve this in different ways.
<span class="mw-page-title-main">Pointer (computer programming)</span> Object which stores memory addresses in a computer program

In computer science, a pointer is an object in many programming languages that stores a memory address. This can be that of another value located in computer memory, or in some cases, that of memory-mapped computer hardware. A pointer references a location in memory, and obtaining the value stored at that location is known as dereferencing the pointer. As an analogy, a page number in a book's index could be considered a pointer to the corresponding page; dereferencing such a pointer would be done by flipping to the page with the given page number and reading the text found on that page. The actual format and content of a pointer variable is dependent on the underlying computer architecture.

In the C++ programming language, a reference is a simple reference datatype that is less powerful but safer than the pointer type inherited from C. The name C++ reference may cause confusion, as in computer science a reference is a general concept datatype, with pointers and C++ references being specific reference datatype implementations. The definition of a reference in C++ is such that it does not need to exist. It can be implemented as a new name for an existing object.

In computer programming, the term hooking covers a range of techniques used to alter or augment the behaviour of an operating system, of applications, or of other software components by intercepting function calls or messages or events passed between software components. Code that handles such intercepted function calls, events or messages is called a hook.

In the area of mathematical logic and computer science known as type theory, a unit type is a type that allows only one value. The carrier associated with a unit type can be any singleton set. There is an isomorphism between any two such sets, so it is customary to talk about the unit type and ignore the details of its value. One may also regard the unit type as the type of 0-tuples, i.e. the product of no types.

A class in C++ is a user-defined type or data structure declared with keyword class that has data and functions as its members whose access is governed by the three access specifiers private, protected or public. By default access to members of a C++ class is private. The private members are not accessible outside the class; they can be accessed only through methods of the class. The public members form an interface to the class and are accessible outside the class.

sizeof is a unary operator in the programming languages C and C++. It generates the storage size of an expression or a data type, measured in the number of char-sized units. Consequently, the construct sizeof (char) is guaranteed to be 1. The actual number of bits of type char is specified by the preprocessor macro CHAR_BIT, defined in the standard include file limits.h. On most modern computing platforms this is eight bits. The result of sizeof has an unsigned integer type that is usually denoted by size_t.

The C and C++ programming languages are closely related but have many significant differences. C++ began as a fork of an early, pre-standardized C, and was designed to be mostly source-and-link compatible with C compilers of the time. Due to this, development tools for the two languages are often integrated into a single product, with the programmer able to specify C or C++ as their source language.

C++11 is a version of the ISO/IEC 14882 standard for the C++ programming language. C++11 replaced the prior version of the C++ standard, called C++03, and was later replaced by C++14. The name follows the tradition of naming language versions by the publication year of the specification, though it was formerly named C++0x because it was expected to be published before 2010.

Substitution failure is not an error (SFINAE) is a principle in C++ where an invalid substitution of template parameters is not in itself an error. David Vandevoorde first introduced the acronym SFINAE to describe related programming techniques.

In computer science, a type punning is any programming technique that subverts or circumvents the type system of a programming language in order to achieve an effect that would be difficult or impossible to achieve within the bounds of the formal language.

In programming languages, particularly the compiled ones like C, C++, and D, linkage describes how names can or can not refer to the same entity throughout the whole program or one single translation unit.

In computer programming, variadic templates are templates that take a variable number of arguments.

In C++ computer programming, allocators are a component of the C++ Standard Library. The standard library provides several data structures, such as list and set, commonly referred to as containers. A common trait among these containers is their ability to change size during the execution of the program. To achieve this, some form of dynamic memory allocation is usually required. Allocators handle all the requests for allocation and deallocation of memory for a given container. The C++ Standard Library provides general-purpose allocators that are used by default, however, custom allocators may also be supplied by the programmer.

Concepts are an extension to the templates feature provided by the C++ programming language. Concepts are named Boolean predicates on template parameters, evaluated at compile time. A concept may be associated with a template, in which case it serves as a constraint: it limits the set of arguments that are accepted as template parameters.

In the C++ programming language, decltype is a keyword used to query the type of an expression. Introduced in C++11, its primary intended use is in generic programming, where it is often difficult, or even impossible, to express types that depend on template parameters.

In C++ computer programming, copy elision refers to a compiler optimization technique that eliminates unnecessary copying of objects.

In computing, sequence containers refer to a group of container class templates in the standard library of the C++ programming language that implement storage of data elements. Being templates, they can be used to store arbitrary elements, such as integers or custom classes. One common property of all sequential containers is that the elements can be accessed sequentially. Like all other standard library components, they reside in namespace std.

C++14 is a version of the ISO/IEC 14882 standard for the C++ programming language. It is intended to be a small extension over C++11, featuring mainly bug fixes and small improvements, and was replaced by C++17. Its approval was announced on August 18, 2014. C++14 was published as ISO/IEC 14882:2014 in December 2014.

References

  1. ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §3.2 One definition rule [basic.def.odr] para. 3
  2. 1 2 ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §3.2 One definition rule [basic.def.odr] para. 4
  3. ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §3.2 One definition rule [basic.def.odr] para. 5
  4. ISO/IEC (1998). ISO/IEC 14882:1998(E): Programming Languages - C++ §9.4.2 Static data members [class.static.data] para. 4
  5. ISO/IEC (1998). ISO/IEC 14882:1998(E): Programming Languages - C++ §3.2 One definition rule [basic.def.odr] para. 2
  6. ISO/IEC (2003). ISO/IEC 14882:2003(E): Programming Languages - C++ §5.19 Constant expressions [expr.const] para. 1
  7. 1 2 "When is a definition of a static data member required?". WG21. Retrieved 2009-04-15.