0%

有关Static类成员变量的外部使用问题

场景说明:

来源于一个配置系统的测试文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "cspch.h"
#include "config.h"
#include "log.h"
#include <yaml-cpp/yaml.h>

CppServer::ConfigVar<int>::ptr g_int_value_config =
CppServer::Config::Lookup("system.port", (int)8080, "system port");

CppServer::ConfigVar<float>::ptr g_float_value_config =
CppServer::Config::Lookup("system.value", (float)10.2f, "system value");

void print_yaml(const YAML::Node& node, int level) {
...
}

void test_yaml() {
...
}

void test_config() {
...
}

int main(int argc, char** argv) {
//test_yaml();
test_config();
return 0;
}

在执行第一个语句的时候进入到 config.h: 34

1
s_datas[name] = v;
  • **config.h**

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #pragma once
    #include ...

    namespace CppServer {

    class ConfigVarBase {
    ...
    };

    template<class T>
    class ConfigVar : public ConfigVarBase {
    ...
    };

    class Config {
    public:
    typedef std::map<std::string, ConfigVarBase::ptr> ConfigVarMap;
    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name,
    const T& default_value, const std::string& description = "") {
    auto tmp = Lookup<T>(name);
    if (tmp) {
    CS_LOG_INFO(CS_LOG_ROOT()) << "Lookup name=" << name << " exists";
    return tmp;
    }

    if (name.find_first_not_of("abcdefghikjlmnopqrstuvwxyz._012345678")
    != std::string::npos) {
    CS_LOG_ERROR(CS_LOG_ROOT()) << "Lookup name invalid " << name;
    throw std::invalid_argument(name);
    }

    typename ConfigVar<T>::ptr v(new ConfigVar<T>(name, default_value, description));
    s_datas[name] = v;
    return v;
    }

    template<class T>
    static typename ConfigVar<T>::ptr Lookup(const std::string& name) {
    auto it = s_datas.find(name);
    if (it == s_datas.end()) {
    return nullptr;
    }
    return std::dynamic_pointer_cast<ConfigVar<T>>(it->second);
    }

    static const std::string OutputConfig();

    static void LoadFromYaml(const YAML::Node& root);
    static ConfigVarBase::ptr LookupBase(const std::string& name);
    private:
    static ConfigVarMap s_datas;
    };

    }
  • **config.cpp** 中完成了对s_datas的初始化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    #include "cspch.h"
    #include "config.h"

    namespace CppServer {

    Config::ConfigVarMap Config::s_datas;

    ...
    ...
    ...

    }

出现 段错误 ,而问题就出在s_datas这个私有静态变量的赋值上

一开始我怀疑是没有链接到config.cpp ,然而在其中我添加了一个简单的测试静态变量型,但却可以在test_config.cpp中全局访问更改,进一步测试发现std::map 类型的复合变量就无法赋值,我进一步怀疑是复合变量没有初始化定义空间

解决方法:

然后我尝试用以下 方案 解决:

将私有静态变量改为私有静态方法,并在其中初始化静态变量,这样保证在第一次调用s_datas的时候一定会先初始化再使用。

config.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
...
~~s_datas[name] = v;~~
GetDatas()[name] = v;
~~~~
return v;
}
...
private:
~~static ConfigVarMap s_datas;~~
static ConfigVarMap& GetDatas() {
static ConfigVarMap s_datas;
return s_datas;
}

config.cpp

1
2
3
4
5
6
7
8
9
10
11
12
#include "cspch.h"
#include "config.h"

namespace CppServer {

~~Config::ConfigVarMap Config::s_datas;~~

...
...
...

}

经过测试此方法可以成功运行,但其原因却依旧没搞懂。