gpt4 book ai didi

c++ - 具有不同内联函数定义的函数对象的实例化取决于链接顺序

转载 作者:行者123 更新时间:2023-11-30 04:40:02 24 4
gpt4 key购买 nike

请帮助我理解以下行为的根本原因。

在文件 a.cpp 中我有:

namespace NS {
struct Obj {
void pong(){ cout << "X in "__FILE__ << endl; }
double k;
};
X::X() { Obj obj; obj.pong(); }
void X::operator()() { cout << "X says hello" << endl; }
}

在文件 b.cpp 中我有:

namespace NS {
struct Obj {
void pong(){ cout << "Y in "__FILE__ << endl; }
bool m;
};
Y::Y() { Obj obj; obj.pong(); }
void Y::operator()() { cout << "Y says hello" << endl; }
}

我的 main 创建一个 X、一个 Y 并调用它们的 operator():

int main( int argc, char *argv[] )
{
NS::X x;
x();

NS::Y y;
y();

return 0;
}

此程序的输出取决于 a.cpp 还是 b.cpp 首先被编译:在第一种情况下,Obj 来自a.cpp 也在 NS::Y 的构造函数中被实例化,在第二种情况下 Obj 来自 b.cppNS::XNS::Y 中被实例化。

% g++ b.cpp a.cpp main.cpp
% ./a.out

X in a.cpp
X says hello
Y in b.cpp
Y says hello

% g++ b.cpp a.cpp main.cpp
% ./a.out

Y in b.cpp
X says hello
Y in b.cpp
Y says hello

在 Linux 或 Visual Studio (2005) 上没有来自链接器的警告。如果我在结构声明之外定义 Obj::pong(),我会收到一个链接器错误,告诉我 Obj::pong 函数是多重定义的。

我进一步试验了一下,发现原因一定与是否内联有关,因为如果我用-O3编译,每个对象都会使用他自己的翻译单元中的Obj。

那么问题就变成了:在非优化编译过程中,内联函数的第二个定义发生了什么?他们被默默地忽略了吗?

最佳答案

这是未定义的行为:您的类定义定义了相同的类类型,因此它们必须相同。对于链接器,这意味着它可以选择一个任意定义作为发出的定义。

如果你想让它们成为分离的类型,你必须将它们嵌套到一个未命名的命名空间中。这将导致该命名空间中的任何内容对于该翻译单元都是唯一的:

namespace NS {
namespace {
struct Obj {
void pong(){ cout << "Y in "__FILE__ << endl; }
bool m;
};
}
Y::Y() { Obj obj; obj.pong(); }
void Y::operator()() { cout << "Y says hello" << endl; }
}

So then the question changes to: what happens to the second definition of the inline function during non-optimized compilation? Are they silently ignored?

是的,对于内联函数(在类定义中定义的函数是内联的,即使没有显式声明为内联),同样的原则适用:它们可以在程序中被定义多次,程序的行为就好像它只是被定义一样一次。对于链接器来说,这意味着它可以丢弃除一个定义之外的所有定义。它选择哪一个是未指定的。

关于c++ - 具有不同内联函数定义的函数对象的实例化取决于链接顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1807523/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com