c++ - g++ 不链接取决于优化设置

标签 c++ c++11 gcc linker

所以,这让我在过去的两天里吃不消:

我无法链接我的应用程序,具体取决于我使用的编译器和使用的优化级别:

  • gcc-O1-O2-O3 配合良好,但与 - 配合时失败O0
  • clang-O2-O3 一起玩得很好,但与 -O1- 一起玩失败O0.

里面有一堆可怕的模板,但我看不出有什么理由会出现这种晦涩的行为。

这是重现问题的最少量代码:

#include <map>
#include <memory>
#include <iostream>

using id_type = long;

class CB : public std::enable_shared_from_this<CB>
{
public:
    CB() = default;
    virtual ~CB() = default;
};

template<class F, class C> class SC : public CB
{
};

class FB
{
public:
    virtual ~FB() = default;
    template<class T, class B> T* as(B* v) const { return dynamic_cast<T*>(v);}
};

template<class T>
class F : public FB
{
public:
    virtual std::shared_ptr<CB> create() const
    {
        auto n = std::make_shared<T>();
        return n;
    }
};

struct  B
{
    virtual ~B() = default;
    static const id_type ID = 1;
};

class A : virtual public B, virtual public SC<A, B>
{
public:
    A() = default;
};

static std::map<id_type, std::shared_ptr<FB>> crtrs {
        {A::ID, std::make_shared<F<A>>()}
    };

int main()
{
    std::cout << crtrs.size();
}

这里和网上一样https://gcc.godbolt.org/z/sb9b5E

错误信息如下:

fld@flap ~/work/p/test1                                                                                                                                                                                                                                                           
> $ g++ -O1 main.cpp                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                          
> $ g++ -O2 main.cpp                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                         
> $ g++ -O3 main.cpp                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                           
> $ g++ -O4 main.cpp                                                                                                                                                                                                                                                                        
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                            
> $ g++ -O0 main.cpp                                                                                                                                                                                                                                                                        
/tmp/cc8D7sNK.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0x1c0): undefined reference to `B::ID'
collect2: error: ld returned 1 exit status
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                            
> $ clang++ -O0 main.cpp                                                                                                                                                                                                                                                                    
/tmp/main-c49b32.o: In function `__cxx_global_var_init.1':
main.cpp:(.text.startup+0x7a): undefined reference to `B::ID'
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                           
> $ clang++ -O1 main.cpp                                                                                                                                                                                                                                                                    
/tmp/main-cf18ee.o: In function `__cxx_global_var_init.1':
main.cpp:(.text.startup+0x3c): undefined reference to `B::ID'
clang-8: error: linker command failed with exit code 1 (use -v to see invocation)
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                            
> $ clang++ -O2 main.cpp                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                             
fld@flap ~/work/p/test1                                                                                                                                                                                                                                                           
> $ clang++ -O3 main.cpp                                                                                                                                                                                                                                                                    
                                                                                     

如果有人知道可能是什么原因,欢迎提供任何提示。

最佳答案

您没有在任何地方提供 B::ID 的定义。碰巧的是,通过更高的优化,编译器碰巧忽略了所有访问。

您需要在顶级范围内添加静态成员的定义:

const id_type B::ID;

如果只读取静态常量数据成员,则不需要单独定义,因为编译时常量不被视为 ODR 使用 (One Definition Rule)。 您根本需要定义的原因是 map 构造函数期望 std::map::value_type在初始化列表中,即 std::pair<const Key, T> .在这种情况下选择的构造函数是 pair( const T1& x, const T2& y ); 为了调用此构造函数地址 A::ID这是B::ID被占用,即使对于常量,也构成 ODR 使用。

因为在这种情况下,对构造函数几乎是微不足道的,所以它在更高的优化下被内联,并且对 &B::ID 的唯一引用消失了,因为 B::ID 的值是已知的,并且可以直接初始化对。

另请参阅:static

如果您使用的是 C++17 或更新版本,您还可以制作 B:ID constexpr而不是 const , 那么你不需要单独定义,因为 constexpr隐式为 inline ( inline static const 也应该没问题)。

关于c++ - g++ 不链接取决于优化设置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63155276/

相关文章:

c++ - 当 printf 正确读取时,std::cout 从 vector 中读取垃圾?

c - 为什么我在尝试创建共享对象时收到 gcc "undefined reference"错误?

c - GCC 按位属性

具有 const 类型或简单类型参数的方法的 C++ 模板函数

c++ - 我可以通过指针传递数组而不传递大小吗?

c++ - 迭代器不会遍历整个 map

c++ - 使用 cmake 生成项目时 Eclipse 索引器正确的 c++11 语法突出显示

c++ - 在 VC++ 中将 void 指针变量类型转换并分配给 Integer 变量。

c++ - 当用户选择一个项目时 QListWidget 移动

c++ - 禁用警告 "deprecated conversion from string constant to ' 字符 *' [-Wwrite-strings]"