具有静态变量的静态内联函数

4

阅读完内联函数中的静态变量后,我编写了以下测试程序:

main.cpp:

#include <iostream>
#include "a.h"
#include "f.h"

void g();

int main()
{
    std::cout << "int main()\n";
    f().info();
    g();
}

a.h:

struct A
{
    A() { std::cout << "A::A()\n"; }
    void info() { std::cout << this << '\n'; }
};

f.h:(由于未命名的命名空间,每个编译单元都是单例局部的)

namespace {
inline A& f()
{
    static A x;
    return x;
}
}

g.cpp:

#include <iostream>
#include "a.h"
#include "f.h"

void g()
{
    std::cout << "void g()\n";
    f().info();
}

问题在于我使用不同的编译器得到的结果不同:
g++ 4.8.2:正常
int main()
A::A()
0x6014e8
void g()
A::A()
0x6014d0

clang++ 3.7.0:通过

int main()
A::A()
0x6015d1
void g()
A::A()
0x6015c1

icpc 15.0.2:在 g() 函数内没有调用 A::A()!

int main()
A::A()
0x601624
void g()
0x601620

这是icpc的一个错误吗?程序的行为没有定义吗?如果我在f.h中用"static"替换"namespace {...}",则g()内会按预期调用A::A()。行为不应该相同吗?
如果我删除f.h中的"namespace {...}",则A::info()会在main()和g()中打印相同的对象地址,并且A::A()只会像预期的那样被调用一次(使用所有编译器)。

1
或许相关:https://dev59.com/zmoy5IYBdhLWcg3wFqFT。你不能真正地说,你没有得到构造函数调用,只是输出没有发生。而且,由于你处于静态构造函数的领域,你可能会遇到另一个错误。 - dhke
该程序已经使用所有编译器编译,并带有“-std=c++11”标准。 - Jac
1
你的源代码和程序输出不匹配。main() 输出 "void g()\n" - Arne Vogel
@Arne 谢谢,已更正。 - Jac
1个回答

3
自从C++11规定未命名命名空间中的名称具有内部链接性质,每个翻译单元都应该拥有自己的f()版本和因此而来的static A x版本。所以gcc和clang是正确的。
看起来icpc没有遵循C++11标准,而是遵循了允许这些名称使用外部链接性质的C++03标准。由于当您明确地使用staticf()变成内部函数时,icpc也会跟随这样做,因此我强烈怀疑这只是一个错误。

该程序已经使用所有编译器编译,并带有“-std=c++11”标准。 - Jac
3
那并不能保护编译器不会出现错误。 - Angew is no longer proud of SO
如果它是外部链接,那么在单个内存位置上会有一个单一对象吗?icpc运行返回两个不同的内存位置。看起来你只是没有在构造函数调用中得到输出... - efunkh
不应该有(也确实没有)每个编译单元(g.cpp和main.cpp)超过1个对象,因为f()在未命名的命名空间中。 - Jac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接