【发布时间】:2012-03-11 00:08:00
【问题描述】:
考虑以下示例:
// usedclass1.hpp
#include <iostream>
class UsedClass
{
public:
UsedClass() { }
void doit() { std::cout << "UsedClass 1 (" << this << ") doit hit" << std::endl; }
};
// usedclass2.hpp
#include <iostream>
class UsedClass
{
public:
UsedClass() { }
void doit() { std::cout << "UsedClass 2 (" << this << ") doit hit" << std::endl; }
};
// object.hpp
class Object
{
public:
Object();
};
// object.cpp
#include "object.hpp"
#include "usedclass2.hpp"
Object::Object()
{
UsedClass b;
b.doit();
}
// main.cpp
#include "usedclass1.hpp"
#include "object.hpp"
int main()
{
Object obj;
UsedClass a;
a.doit();
}
代码编译时没有任何编译器或链接器错误。但是输出对我来说很奇怪:
-
Fedora x86_64 上的 gcc (Red Hat 4.6.1-9) 没有优化 [EG1]:
UsedClass 1 (0x7fff0be4a6ff) doit hit
UsedClass 1 (0x7fff0be4a72e) doit hit -
与 [EG1] 相同,但启用了 -O2 选项 [EG2]:
UsedClass 2 (0x7fffcef79fcf) doit hit
UsedClass 1 (0x7ffffcef79fff) doit hit -
msvc2005 (14.00.50727.762) 在没有优化的 Windows XP 32 位 [EG3]:
UsedClass 1 (0012FF5B) doit hit
UsedClass 1 (0012FF67) doit hit -
与 [EG3] 相同,但启用了 /O2(或 /Ox)[EG4]:
UsedClass 1 (0012FF73) doit hit
UsedClass 1 (0012FF7F) doit hit
我希望链接器错误(假设违反了 ODR 规则)或 [EG2] 中的输出(内联代码,没有从翻译单元导出,保留 ODR 规则)。因此我的问题是:
- 为什么输出 [EG1]、[EG3]、[EG4] 可能?
- 为什么我从不同的编译器甚至从同一个编译器得到不同的结果?这让我觉得标准在这种情况下没有指定行为。
感谢您的任何建议、cmets 和标准解释。
更新
我想了解编译器的行为。更准确地说,如果违反 ODR,为什么不会产生错误。一个假设是,由于类 UsedClass1 和 UsedClass2 中的所有函数都被标记为内联(因此 C++03 3.2 未违反)链接器不报告错误,但在这种情况下输出 [EG1]、[EG3]、[EG4] 看起来很奇怪。
【问题讨论】:
-
违反了 ODR,当发生这种情况时,您不能保证链接器错误。行为未定义。
-
我无法回答您有关标准的问题,但这就是我们有命名空间的原因。