0

为什么以下代码会生成这样的输出?

main.cpp ctor 0x24a4c30
test.cpp dtor 0x24a4c30

测试.cpp

#include <boost/optional.hpp>

struct Test
{
    Test()
    {
        printf("test.cpp ctor %p\n", (void *) this);
    }

    ~Test()
    {
        printf("test.cpp dtor %p\n", (void *) this);
    }
};

boost::optional< Test > t;

主文件

#include <memory>

struct Test
{
    Test()
    {
        printf("main.cpp ctor %p\n", (void *) this);
    }

    ~Test()
    {
        printf("main.cpp dtor %p\n", (void *) this);
    }
};

int
main(void)
{
    std::make_shared< Test >();
    return 0;
}

编译

g++ -std=c++11 -c test.cpp -o test.o
g++ -std=c++11 -c main.cpp -o main.o
g++ -std=c++11 test.o main.o

我解释了test.o提供 Test 的ctor & dtor然后链接器丢弃来自main.o的重复符号的这种行为,但它仅适用于dtor。如果我删除静态对象t那么链接器会丢弃test.o中的符号,输出是下一个

main.cpp ctor 0x208ec30
main.cpp dtor 0x208ec30
4

1 回答 1

0

如评论中所述,在两个链接的翻译单元中定义相同的符号违反了单一定义规则,而

一个程序中可以有多个定义,只要每个定义出现在不同的翻译单元中,下面的每一个:类类型、枚举类型、具有外部链接的内联函数、具有外部链接的内联变量(从 C+ +17)、类模板、非静态函数模板、类模板的静态数据成员、类模板的成员函数、部分模板特化、概念 (C++20 起),只要满足以下所有条件:

  • 每个定义都由相同的标记序列组成(通常出现在同一个头文件中)
  • [...]

如果满足所有这些要求,则程序的行为就好像整个程序中只有一个定义。否则,行为是 undefined(强调我的)

UB的观察结果不需要解释,也可能没有。

当然,这是明目张胆的违规行为。但是,在看起来更无辜的程序中可能会出现非常相似的情况(并导致奇怪且难以定位的错误)。例如,当某些类声明发生更改时,链接到较旧的单独编译的对象。

于 2018-02-10T21:02:29.143 回答