ProgrammingLead C++ Developer

What is the 'One Definition Rule (ODR)' problem in C++? How does it affect large projects and how can violations be avoided?

Pass interviews with Hintsage AI assistant

Answer

One Definition Rule (ODR) is a fundamental rule of C++ that requires that within the entire program (across all translation units), there is exactly one definition for each object, function, or class.

ODR is violated if:

  • Multiple definitions of the same function/class with different code appear in different .cpp files.
  • An inline function or template has different implementations at different include points.

This leads to subtle, unpredictable bugs, incorrect linking, or worse, varying behavior of the program depending on how it was compiled.

Why violations occur:

In large projects, .h files are often copied/modified without version control, or code is separated into many modules with separate compilation. If someone changes an inline function in only one place, other source files may still have the old version.

How to avoid:

  • Do not define functions outside a class in a .h file unless they are inline.
  • Use include guards and control a single definition point.
  • For constant variables, use constexpr or, with C++17, inline variables.

Trick Question

Can static functions (static void foo()) with the same names and different implementations be defined in different .cpp files without consequences?

Many believe that static functions do not affect each other across modules at all. The answer is yes, they can, because each has internal linkage (visible only within its translation unit). However, this is not guaranteed for inline functions and templates, which is often confused.

Example:

// file1.cpp static void foo() { std::cout << "A"; } // file2.cpp static void foo() { std::cout << "B"; }

Calls in these modules will be independent.

Examples of real errors due to ignorance of the topic's nuances


Story

In a large project, one developer changed the body of an inline function in only one of the clone .h files. After compilation, some behavior became unpredictable: some modules were operating under the old algorithm, while others were following the new one. The reason was an ODR violation for the inline function.



Story

During the migration to C++17, a constant variable was defined in several header files without using the inline keyword. During linking, many duplicate symbol errors appeared. It was fixed by declaring the variable as inline const.



Story

It was discovered too late that the generated .h file of the build system contained two implementations of the same method of a template class, differing by one ifdef check in different builds. Later, the application periodically crashed due to ABI mismatches between the linked modules.