One definition rule in c++

[亡魂溺海] 提交于 2019-11-29 18:03:10

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 ints 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 { ... };
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!