为什么ld链接器允许使用相同方法的多个类定义?

Raf*_*cki 18 c++ linker g++ ld

考虑这个文件,first.cpp包含一个类定义并使用:

#include <iostream>

struct Foo
{
    Foo(){ std::cout << "Foo()" << std::endl; }
    ~Foo(){ std::cout << "~Foo()" << std::endl; }
};

int main(){
    Foo f;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

和另一个,second.cpp包含冲突的类定义:

#include <iostream>

struct Foo
{
    Foo();
    ~Foo();
};

Foo::~Foo(){ std::cout << "wrong ~Foo()" << std::endl; }
Run Code Online (Sandbox Code Playgroud)

当有两个定义了相同名称的函数时,链接器会抱怨重复的符号,但这些具有重复类方法的文件在没有错误的情况下编译.

我用这些命令编译:

$ g++ -c second.cpp -o second
$ g++ second first.cpp -o first
Run Code Online (Sandbox Code Playgroud)

将参数重新排序到第二个g++调用不会更改输出.

first运行时,这是输出:

$ ./first
Foo()
wrong ~Foo()
Run Code Online (Sandbox Code Playgroud)

为什么链接器允许重复的类方法?如果显然允许,为什么wrong ~Foo()打印?

Dav*_*eas 15

再次,未定义的行为.您的程序有多个析构函数定义Foo,这意味着它违反了ODR.该计划是错误的,任何事情都可能发生.

链接器为什么不拿起它?当在类定义中定义函数时,它是隐式的inline.编译器通常将这些函数标记为"弱符号".然后链接器获取所有转换单元并尝试解析符号.如果需要,链接器将丢弃弱符号(即,如果符号已在其他位置定义).

从程序的实际输出开始,看起来编译器实际上没有内联对构造函数的调用,因此在运行时调度到链接器留下的符号(非弱的符号)


为什么链接器允许重复方法?

因为所有(但最多只有一个)是弱符号(即inline)

为什么,在这种情况下,错误~Foo()被打印?

因为调用没有内联,并且链接器删除了弱符号