c++ - 如何修复静态类成员的初始化顺序?

标签 c++ static-members variable-initialization

以下代码是抛出 SIGSEGV 还是按预期工作取决于目标文件在 makefile 中出现的顺序(在我的例子中是 .pro)。我不是很有信心只需要按正确的顺序维护它们。是否对我的源代码进行了简单的更改,从而消除了对目标文件正确顺序的依赖?

这些是源文件,归结为一个简短的例子。

dummy0.h :

#ifndef DUMMY0_H
#define DUMMY0_H

#include <QObject>

class Dummy0 : public QObject
{
    Q_OBJECT
public:
    explicit Dummy0(QObject *parent = 0);
};

#endif // DUMMY0_H

dummy0.cpp :

#include "dummy0.h"
#include "unittestclass.h"

Dummy0::Dummy0(QObject *parent) : QObject(parent) {}

ADD_TEST( Dummy0 )

顾名思义,以后还会有Dummy1 ... Dummy<n> .

unittestclass.h :

#ifndef UNITTESTCLASS_H
#define UNITTESTCLASS_H

#include <QObject>
#include <QTest>
#include <QDebug>
#include <memory>
#include <list>

// see https://stackoverflow.com/questions/12194256/qt-how-to-organize-unit-test-with-more-than-one-class

namespace TestCollector {

  class BaseClass {  // see https://hackernoon.com/shared-static-variable-for-all-template-class-instances-eaed385f332b
  public:
      BaseClass() = default;
      int listClasses( int argc, char *argv[] );
  protected:
      static std::list<std::shared_ptr<QObject>> testlist;
  };

  template <class T>
  class UnitTestClass : public BaseClass {

  public:
      UnitTestClass() {
          std::shared_ptr<QObject> ptr = std::make_shared<T>();
          qDebug() << "pushing a" << ptr.get()->metaObject()->className();
          qDebug() << "testlist size before:" << testlist.size() << "of" << testlist.max_size();
          testlist.size();  // no SIGSEGV !?
          testlist.push_back( ptr );   // SIGSEGV here when race condition
          qDebug() << "testlist size after:" << testlist.size();
      }
  };
}  // TestCollector

#define ADD_TEST(className) static TestCollector::UnitTestClass<className> test;

#endif // UNITTESTCLASS_H

unittestclass.cpp :

#include "unittestclass.h"

namespace TestCollector {

std::list<std::shared_ptr<QObject>> BaseClass::testlist;

int BaseClass::listClasses( int argc, char *argv[] ) {
    int result=0;

    for( const auto c : testlist ) {
        qDebug() << "got" << c.get()->metaObject()->className();
    }
    return result;
}

}  // TestCollector

main.cpp :

#include "unittestclass.h"

int main(int argc, char *argv[]) {
    TestCollector::BaseClass base;
    return base.listClasses( argc, argv );
}

当我有 dummy0.cpp之前unittestclass.cpp程序在 testlist.push_back(ptr) 处失败[注意:有趣的是,testlist.size()push_back 之前的行中不会失败]。当dummy0.cpp后来出现,一切都很好。这暗示了一个问题,当目标文件的顺序不利时,可能会在初始化之前使用 teSTList!?

如何避免依赖于此顺序?

[我目前使用的是 c++11、QtCreator 3.5.1、g++5.4.0、GNU ld 2.26.1。]

最佳答案

您可以通过函数间接确保您所依赖的对象存在:

class BaseClass
{
// ...
    // This returns a pointer only to make it hard to copy the list by mistake.
    // Some people prefer to use a reference, and some prefer dynamic allocation.
    // The important part is that the object is created the first time you use it.
    static std::list<std::shared_ptr<QObject>>* get_testlist()
    {
        static std::list<std::shared_ptr<QObject>> tests;
        return &tests;
    } 
};

然后像这样使用它:

UnitTestClass() {
      std::shared_ptr<QObject> ptr = std::make_shared<T>();
      qDebug() << "pushing a" << ptr.get()->metaObject()->className();
      auto testlist = get_testlist();
      qDebug() << "testlist size before:" << testlist->size() << "of" << testlist->max_size();
      testlist->push_back( ptr );
      qDebug() << "testlist size after:" << testlist->size();
  } 

关于c++ - 如何修复静态类成员的初始化顺序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54788022/

相关文章:

C# 静态类成员和 System.Windows.Controls.Image 性能问题

typescript - 从 typescript 中的非静态函数访问静态成员

c# - switch 语句中的这个变量如何在没有声明的情况下看似使用?

swift - init let 变量基于 bool 值

java - 为什么Java中变量必须初始化为默认值

c++ - 为什么这种 stringstream 的用法在 linux 上不起作用,但在 Mac 上却起作用?

c++ - qProcess写关闭写 channel 后

C++ - enum vs. const vs. #define

c++ - 为什么 "std::vector<bool>"的大小是 16 Byte?

java - 写入静态字段 - 在这种情况下 FindBugs 是错误的吗?