错误:非常量静态数据成员必须在行外初始化

Jas*_*rya 7 c++ static class

class Solution {
    public:

     static int m=INT_MIN; // it shows error: non-const static data member must 
                               be initialized out of line.(why?)
                                  using "int m=INT_MIN" is fine. 
      int func(TreeNode*root){
        if(root==NULL){
            return 0;
        }

        int l=max(func(root->left),0);
        int r=max(func(root->right),0);

        m=max(l+r+root->val,m);

        return max(l,r)+root->val;

    }


    int maxPathSum(TreeNode* root) {

        if(root==NULL)
        {
         return 0;
        }
        m=INT_MIN;
        int x=func(root);
        return m;

    }
};
Run Code Online (Sandbox Code Playgroud)

我需要更新 variable 的值m。因此我使用static int数据类型。但是下面的错误来了。使用int而不是static int工作正常。但是为什么会static int报错呢?

编译错误

Sch*_*eff 21

回答OP的问题为什么

\n
class Solution {\n  public:\n    int m = INT_MIN;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

很好但是

\n
class Solution {\n  public:\n    static int m = INT_MIN;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

不是:

\n

简而言之:给数据成员添加前缀从static根本上改变了它的含义。

\n

如果没有static,成员变量是类的一部分,每个实例都会为此成员变量提供单独的存储。

\n

使用 时static,成员变量仅具有类的范围,但只有一个全局存储。

\n

分别来说,初始化也有不同的含义。

\n

对于非静态成员变量,它提供了构造函数可以使用(或覆盖)的默认初始化。

\n

举例演示:

\n
#include <iostream>\n\nenum ArgCase1 { Case1 };\nenum ArgCase2 { Case2 };\n\nclass Solution {\n  public:\n    int m = 123;\n    \n    Solution() = default; // will use m(123) implicitly\n    Solution(ArgCase1) { } // will use m(123) implicitly\n    Solution(ArgCase2): m(456) { } // default of m ignored\n};\n\n#define DEBUG(...) std::cout << #__VA_ARGS__ << ";\\n"; __VA_ARGS__ \n\nint main()\n{\n  DEBUG(Solution sol);\n  std::cout << "sol.m: " << sol.m << \'\\n\';\n  DEBUG(Solution sol1(Case1));\n  std::cout << "sol1.m: " << sol1.m << \'\\n\';\n  DEBUG(Solution sol2(Case2));\n  std::cout << "sol2.m: " << sol2.m << \'\\n\';\n}\n
Run Code Online (Sandbox Code Playgroud)\n

输出:

\n
class Solution {\n  public:\n    int m = INT_MIN;\n};\n
Run Code Online (Sandbox Code Playgroud)\n

coliru 上的现场演示

\n

对于static成员变量来说,初始化是很危险的。假设一个类在多次包含的标头中声明,这将导致违反“单一定义规则”

\n

以前,通常在标头中声明成员变量,但在文件(代表翻译单元)中定义它。static.cpp

\n

示例:

\n

solution.h:

\n
#ifndef SOLUTION_H\n#define SOLUTION_H\n\nclass Solution {\n  public:\n    static int m;\n};\n\n#endif // SOLUTION_H\n
Run Code Online (Sandbox Code Playgroud)\n

solution.cc:

\n
// header of this module:\n#include "solution.h"\n\nint Solution::m = 123;\n
Run Code Online (Sandbox Code Playgroud)\n

coliru 上的现场演示

\n

从 C++17 开始,可以使用关键字 \xe2\x80\x93 来使用新的替代方案inline

\n

来自cppreference.com \xe2\x80\x93 静态成员 \xe2\x80\x93 静态数据成员

\n
\n

静态数据成员可以声明为内联。内联静态数据成员可以在类定义中定义,并且可以指定初始值设定项。它不需要类外定义

\n
\n

例子:

\n

solution.h:

\n
#ifndef SOLUTION_H\n#define SOLUTION_H\n\nclass Solution {\n  public:\n    inline static int m = 123;\n};\n\n#endif // SOLUTION_H\n
Run Code Online (Sandbox Code Playgroud)\n

coliru 上的现场演示

\n

优点是不需要.cpp为此文件,即它class Solution可以作为仅标头源提供。

\n

  • 内联声明完成了这项工作!谢谢。 (3认同)

Dev*_*rya 9

Bjarne Stroustrup在这里解释了这一点

类通常在头文件中声明,而头文件通常包含在许多翻译单元中。但是,为了避免复杂的链接器规则,C++ 要求每个对象都有唯一的定义。如果 C++ 允许需要作为对象存储在内存中的实体的类内定义,那么这条规则就会被打破。

正如 Stroustrup 所说,每个类都需要一个唯一的定义。现在,我们知道静态成员直接与其类相关联。现在考虑两种情况:

  1. static成员还constant,那么它的初始化直列允许的,因为编译器可以做出自己的优化,并因为它保证了它的价值不会改变对待这个成员作为一个编译时间常数。因此,由于该成员的值是固定的,因此该成员所关联的类的定义也是固定的。因此,允许内联初始化。

  2. static构件是不恒定的。然后它的值可以在程序执行期间更改。因此,编译器无法对这个成员进行编译时优化。因此,为了防止在加载类时尝试初始化此类成员时可能出现的复杂情况,不允许对此类成员进行内联初始化。

PS:第一次听说这个概念的时候,我也很困惑,因为它不符合程序员所希望的正交性原则。正交性原则将说明,由于我们可以组合intstatic;和intconst,我们应该能够编写static const intstatic int以类似的方式。但这里的这种情况是一种情况的例子,语言的开发人员必须放弃语言用户的正交性,以换取编译过程的简单性。

这里查看正交性的概念