According to the c++ standard:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type, or template.
//--translation_unit.cpp--//
int a;
void foo()
{
int a; //Second defention of a. ODR fails.
}
Can you explain me how ODR does work actually?
This doesn't break the rule because you define two different variables. They have the same name, but are declared in different scopes, and so are separate entities. Each has a single definition.
The declaration in the function's scope is said to hide the one in the global namespace. Within the function, the unqualified name a
refers to the local variable, while the qualified name ::a
refers to the global.
You did not define a
again.
You just defined a new variable a
. It has the scope only inside the function, and has nothing to do with the original one(which has a global scope), and shadowed the original one inside the function.
They do not violate the ODR because they have different scope.
The first a
has global scope
A variable that has global scope (also termed file scope) is known throughout the file after the point where it is defined
The second a
has local scope
A variable that has local scope (also termed block scope) is known only within the block in which it is defined
For understand more clear about ODR of C++ the concepts you should investigate are: Storage Duration, Scope, and Linkage
Can you explain me how ODR does work actually?
Here is an example of violation of ODR:
/* file : module.cpp */
#include <stdio.h>
inline int foo() {
printf("module.foo: %p\n", &foo);
return 1;
}
static int bar = foo();
/* file : main.cpp */
#include <stdio.h>
inline int foo() {
printf("main.foo: %p\n", &foo);
return 2;
}
int main(int argc, char *argv[]) {
return foo();
}
As you can see, function int foo()
defined differently in two modules. Now observe, how it produces different behavior depending on requested optimization level (O3 vs O0):
$ clang++ --std=c++11 -O0 main.cpp module.cpp && ./a.out
module.foo: 0x100a4aef0
module.foo: 0x100a4aef0
$ clang++ --std=c++11 -O3 main.cpp module.cpp && ./a.out
module.foo: 0x101146ee0
main.foo: 0x101146ee0
Output is different, because for inline functions compiler produces a linker symbol in each compilation module. This symbol (in each compilation module) is marked as "pick any, they are all the same". In the first case, when all optimizations are disabled, linker picks up definition from module.cpp. In the second case, compiler just inlines both functions so no additional work from linker is required.
There are other examples when violation of ODR produces weird behavior. So, don't do it :)
P.S. Bonus, case from real life:
/* a.cpp */
struct Rect
{
int x,y,w,h;
Rect(): x(0),y(0),w(0),h(0)
};
/* b.cpp */
struct Rect
{
double x,y,w,h;
Rect(): x(0),y(0),w(0),h(0)
};
The problem here is the same as in previous example (because Rect constructors are implicitly inline). Depending on phase of the moon compiler was picking one implementation or another producing strange results (int
version will leave part of doubles
uninitialized, double
version will go outside of int
s and corrupt memory there). Good way to protect from that is to use anonymous namespaces (C++) or declare struct as static
(C):
/* file.cpp */
namespace {
struct Rect { ... };
}
/* file.c */
static struct Rect { ... };
来源:https://stackoverflow.com/questions/23624844/one-definition-rule-in-c