【问题标题】:Why we need a separate definition for a static const data member?为什么我们需要为静态 const 数据成员单独定义?
【发布时间】:2021-06-27 23:24:04
【问题描述】:

您好,如果我有一个 static const 数据成员,那么我可以为它提供一个类内初始化程序,我不需要在类主体之外再次定义它。

  • 但只有在类范围内使用该常量并且如果在外部使用时,必须在外部提供单独的定义,否则对它的任何引用都会导致链接时错误:“未定义对静态对象的引用:x” .

      struct Foo{
          static int const sz_ = 100;
          std::array<int, sz_> ai_100{};
      };
    
      //int const Foo::sz_;
    
      int main(){
    
          float pts[Foo::sz_]{}; // ok
          void bar(int const&); // defined later on
          bar(Foo::sz_); // undefined reference to Foo::sz_
      }
    
      void bar(int const&){
          //do_something
      }
    
  • 为什么在类范围之外使用static const数据成员sz_作为数组大小是OK的?

  • 为什么当将sz 传递给函数bar 时,该函数采用对const 的左值引用,链接器无法链接并抱怨Foo::sz_ 的定义?

  • 函数bar 接受一个对const int&amp; 的左值引用,因此它可以从一个右值初始化,那么为什么它对初始化器Foo::sz_ 的定义很重要?

【问题讨论】:

    标签: c++ static constants in-class-initialization


    【解决方案1】:

    为什么我们需要为静态 const 数据成员单独定义?

    首先,我们必须记住单一定义规则。它实际上是一组规则,但我们对此上下文感兴趣的规则的简化版本是:每个变量都必须有一个定义

    其次,我们应该考虑到类通常用于多个翻译单元。

    如果静态成员变量的声明是一个定义,那么每个包含类定义的翻译单元都将包含该变量定义。这与 ODR 相悖,链接器不知道该怎么做。

    因此,必须有一个单独的变量定义,允许将类定义包含在多个翻译单元中,同时将单独的变量定义保留在一个翻译单元中。


    虽然过去的语言实现可能无法处理多个定义(早在模板出现在 C++ 之前),但现在它们可以了,并且该语言已被扩展(在 C++17 中)以允许内联定义的变量。 inline 关键字对变量的含义与对函数的含义相同:它放宽了单一定义规则,允许(也要求)在每个 TU(使用 odr 的地方)中定义变量。

    【讨论】:

      【解决方案2】:

      主要是出于历史原因。盯着 C++17,你可以拥有inline data members。而constexpr 成员默认为inline

      【讨论】:

        【解决方案3】:

        您的非链接示例可以简化为:

        struct Foo{
            static int const sz_ = 100;
        };
        
        int main(){
            int const *p = &Foo::sz_;   // undefined reference to Foo::sz_
        }
        

        换句话说,如果我们获取Foo::sz_的地址,或者为其分配一个引用(这是一个非常相似的操作,在底层),那么我们需要在某个地方定义int const Foo::sz_;

        这是为什么?好吧,如果我们只使用Foo::sz_,那么编译器就不需要变量了。它可以只使用 100 作为有效的文字。但是如果我们想获取它的地址,那么我们需要一个实际的变量来引用。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2017-10-11
          • 1970-01-01
          • 2012-04-04
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多