通过调用 C++ 中的静态类函数初始化全局静态变量

Posted

技术标签:

【中文标题】通过调用 C++ 中的静态类函数初始化全局静态变量【英文标题】:Global static variable initialised with a call to static class function in 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 中可以重现)

【问题讨论】:

【参考方案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() (这样我将保证在向量析构函数之前调用析构函数)。当然,使用智能指针也有助于避免这个问题。

以上是关于通过调用 C++ 中的静态类函数初始化全局静态变量的主要内容,如果未能解决你的问题,请参考以下文章

C++中,类内的成员变量自动初始化为零吗,而全局变量随意赋值

C++中的静态全局变量

C++面向对象-static、const

静态局部变量

c++中关于私有静态变量的问题

c++ 面向对象的静态函数 多线程调用