Question

This post reference to the One Definition Rule.

Wikipedia is pretty bad on explaining how to implement it

Where can I find good ressources about guidelines to follow in C++ .NET?

Was it helpful?

Solution

The one definition rule basically means that a variable/function can only be located at one place in address space of the compiled executable. One way to think of it is while you compile, there is an array of memory to be used in the compiled program (object code), and a lookup table to reference variable/function locations. This is done on a per process level. Suppose that the following is a simple program:

file1.cpp

int square(int x); // this is a declaration
extern int someVariable; // this is a declration

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file2.cpp

int square(int x); // this is a declaration

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}       

When the compiler starts compiling the object code, it reads in the declarations, and puts thing in its table. AT the end of compiling file1.cpp, it will end up with something like this:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    12 34 56 78 aa XX XX XX XX ab cd
definition:
    square: starts at address 0

This assumes that the function gets compiled to those particular assembly instructions. At linker time, XX XX XX XX will get replaced by the address of someVariable.

File2 ends up something like:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    00 00 00 00 12 34 56 78 12 34 56 YY YY YY YY 23 21
definitions:
    someVariable: starts at address 0
    main: starts at address 4

And in this case, the YY will be replaced by the address of square.

That's where the linker comes into play. The linker's job is to go through the list, and build up a table of where everything is in the address space of the program at compile time. However, there is a problem if two object files have the same definition of a variable when it tries to link. If there were two definitions of someVariable in the above example, then it wouldn't know what to replace YY with. Likewise, if there's no definition, then you get ugly linker errors.

The "solution" to the rule is to partition your file such that you have definitions only in .cpp files, and have declarations of things in your .h files, so the example above would become:

file1.cpp

#include "file2.h"

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file1.h

int square(int x); // this is a declaration

file2.cpp

#include "file1.h"

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}

file2.h

extern int someVariable;

Note that this is an incredibly simple example, and that it doesn't really apply in .NET since there isn't a concept of a distinction between a declaration and definition.

OTHER TIPS

The easiest way to comply with the one definition rule is to put the definition in a .cpp file instead of the header.

People sometimes put definitions into headers using macros and/or preprocessor conditionals to make the object or function defined only in one compilation unit. But it's easier usually (and certainly more understandable) to just put the definition in a .cpp file.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top