【问题标题】:Global static variable initialised with a call to static class function in c++通过调用 C++ 中的静态类函数初始化全局静态变量
【发布时间】:2017-04-02 16:46:22
【问题描述】:

不确定问题的表述是否正确,但问题就在这里。

我有一个静态库,其中我在 a.h 中有以下类:

#pragma once
#include <vector>
class A{
public:
 void Run() {
  data_.push_back(10);
  std::cout << "size: " << data_.size() << std::endl;
 }
private:
 static std::vector<int> data_;
};

a.cpp如下:

#include "a.h"
std::vector<int> A::data_;

我在 b.h 有另一门课:

#pragma once
#include <string>
class B
{
  public:
    static std::string Get();
};

和 b.cpp:

#include "b.h"
#include "a.h"
std::string B::Get()
{
  static A a;
  a.Run();
  return "foo";
}

现在我使用上述静态库的主要应用程序如下:

#include <iostream>
#include "a.h"
#include "b.h"

static std::string var1= B::Get();

int main(int argc, char** argv)
{
  A a;
  a.Run();
}

试图理解为什么输出是:

尺寸:1

尺寸:1

整个类的每个静态数据成员都应该有一个实例,因此应该只调用一次 A::data_ 构造函数。 我在打"static initialization order fiasco"吗? IE。 data_ 在我使用它之前没有初始化,但是我应该会崩溃吗?

现在让我们想象一下我的 data_ 包含动态初始化的项目(没有 POD)。如果最后 data_ 包含一个项目,它将如何被破坏,尽管我已经插入了 2?

这就是我现实生活中的代码中实际发生的情况(它有时会在破坏数据时崩溃_)。

摆脱全局静态( static std::string var1= B::Get(); )解决了问题,但我仍然想了解引擎盖下的问题。

所描述的案例可以在 VS2015 中重现(真实案例在 gcc 6.2 中可以重现)

【问题讨论】:

    标签: c++ static global-variables static-libraries


    【解决方案1】:

    我是不是遇到了“静态初始化顺序惨败”?

    很有可能。

    您可以通过函数调用使类的static 数据可用,从而消除该问题。例如

    class A{
    public:
     void Run() {
      getData().push_back(10);
      std::cout << "size: " << getData().size() << std::endl;
     }
    private:
     static std::vector<int>& getData();
    };
    
    std::vector<int>& A::getData()
    {
       static std::vector<int> data;
       return data;
    }
    

    当你这样做时,data 将在第一次调用 A::getData() 时被初始化。它完全消除了静态初始化顺序问题。

    【讨论】:

    • @R Sahu,是的,您的建议确实解决了这个问题。尽管还有一个更重要的细节:如果在类的析构函数中需要调用任何静态函数,请确保在构造函数中进行相同的调用,否则它可能已经被析构了。
    • @Tadzys,我不记得在函数内部构造和销毁static 对象是一个问题,如果您遇到任何问题,请在另一个帖子中详细说明。跨度>
    • @R Sahu,可以说我的 getData 持有静态 std::vector
    • @Tadzys,这表明设计不佳。将指针存储在静态对象中并不是一个好主意。您可以想出复杂的逻辑来处理它们,但如果可以的话,请避免使用它们。请改用std::vector&lt;std::vector&lt;int&gt;&gt;
    • @R Sahu,可以说 getData 持有静态 std::vector 并且在析构函数中我想清理向量,但 getData() 在构造函数之前被调用(构造函数可能不是根本没有调用),因此您将遇到泄漏或崩溃。我的具体解决方案是在构造函数中调用 getData() (这样我将保证在向量析构函数之前调用析构函数)。当然,使用智能指针也有助于避免这个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-21
    • 2011-06-28
    相关资源
    最近更新 更多