简体   繁体   English

跨多个源文件构建C ++静态数组

[英]Building C++ Static Array Across Multiple Source Files

I have a system that looks something like this: 我有一个看起来像这样的系统:

Master.h 硕士

extern const Activators[2];

Master.cpp Master.cpp

#include <TypeOne.h>
#include <TypeTwo.h>
const Activators[2] = { &TypeOne::Create, &TypeTwo::Create };

Where you can imagine TypeOne and TypeTwo are classes with a static Create method that returns a new instance. 您可以想象TypeOne和TypeTwo是带有静态Create方法的类,该方法返回一个新实例。

I'm looking for a way to decompose this system such that there doesn't need to be a single file that creates a link-time dependency on all of the types. 我正在寻找一种分解该系统的方法,这样就不需要一个文件就可以对所有类型创建链接时依赖性。

I'd like to be able to link together a unit test with just TypeOne's object file and a version of the static Activators array that is only filled with the function pointer to TypeOne's Create method. 我希望能够将单元测试与TypeOne的目标文件和仅使用指向TypeOne的Create方法的函数指针填充的静态Activators数组版本链接在一起。

Is there a way in C++ to create a statically-defined array and then fill individual slots in that array across compilation units? 在C ++中,有没有一种方法可以创建一个静态定义的数组,然后在整个编译单元中填充该数组中的各个插槽? Ideally I'd be able to have something like this: 理想情况下,我可以拥有这样的东西:

Master.cpp Master.cpp

const Activators[2];

TypeOne.cpp TypeOne.cpp

Activators[0] = &TypeOne::Create;

TypeTwo.cpp TypeTwo.cpp

Activators[1] = &TypeTwo::Create;

Yes. 是。 Although you need to be very careful. 虽然您需要非常小心。

TypeOne.cpp

namespace {
    class BeforeMain {
        BeforeMain() {
            Activators[0] = &TypeOne::Create;
        }
    };

    BeforeMain obj;
}

TypeTwo.cpp

namespace {
    class BeforeMain {
        BeforeMain() {
            Activators[1] = &TypeTwo::Create;
        }
    };

    BeforeMain obj;
}

Then, other than this, just don't access the array until main() is called. 然后,除此以外,直到调用main()才访问数组。

Personally though, I'd rather see Activators be a std::vector<T> , and then have each BeforeMain use std::vector<T>::push_back() . 不过,就我个人而言,我宁愿将Activators设为std::vector<T> ,然后让每个BeforeMain使用std::vector<T>::push_back()

Assuming that Activators are a polymorhpic (where Type1 and Type2 both derive from Activators ) type, I would approach the problem like this. 假设Activators是多态的( Type1Type2都从Activators派生)类型,我将解决这种问题。

Activators.h Activators.h

std::vector<std::unique_ptr>>& activators();

Activators.cpp Activators.cpp

std::vector<std::unique_ptr>>& activators()
{
   static std::vector<std::unique_ptr>> the_array(2);
   return the_array;
}

Then in individual compilation units you can assign whatever you want: 然后,您可以在各个编译单元中分配所需的任何内容:

Type1.cpp Type1.cpp

#include "Activators.h"

struct setup_activator_type_1
{
    setup_activator_type_1()
    {
       activators()[0].reset(new Type1);
    }
};

static setup_activator_type_1 type1_static_initializer;

I would provide a functional interface to add Activators and use it from TypeOne.cpp and TypeTwo.cpp . 我将提供一个功能接口来添加Activators ,并从TypeOne.cppTypeTwo.cpp中使用它。

In Activators.h : Activators.h中

void addActivator(Activator activator);

In Activators.cpp : Activators.cpp中

static std::vector<Activator> activators{};

void addActivator(Activator activator)
{
   activators.push_back(activator);
}

In TypeOne.cpp : TypeOne.cpp中

struct Initializer
{
   Initializer()
   {
      addActivator(&TypeOne::Create);
   }
};

static Initializer initializer;

In TypeTwo.cpp : TypeTwo.cpp中

struct Initializer
{
   Initializer()
   {
      addActivator(&TypeTwo::Create);
   }
};

static Initializer initializer;

The way C++ initializes globals is really weird, and technically the other answers thus far have undefined behavior, though will probably work on your machine/compiler anyway. C ++初始化全局变量的方式确实很奇怪,从技术上讲,到目前为止,其他答案都具有未定义的行为,尽管无论如何仍然可以在您的机器/编译器上使用。 Basically, the problem is that when the program starts, the implementation is only required to initialize the globals in main.cpp and it's headers. 基本上,问题在于,当程序启动时,只需执行即可初始化main.cpp及其标头中的全局变量。 When your code calls a function that's defined in another cpp/header combo (translation unit), only then is C++ required to initialize the globals in that one translation unit . 当您的代码调用在另一个cpp / header组合(转换单元)中定义的函数时, 只有 C ++才需要在该转换单元中初始化全局变量。

The easiest (safe) workaround in your particular case , is to simply do the initialization in the header. 您的特定情况下 ,最简单(安全)的解决方法是仅在标头中进行初始化。 If a file has include "TypeOne.h" , it will initialize Activators[0] itself. 如果文件include "TypeOne.h" ,它将初始化Activators[0]本身。 To be portable, it's important that the translation unit (cpp file) that contains int main() also includes the headers for all of these that you need to use. 为了便于移植,包含int main()的转换单元(cpp文件int main()还必须包含所有需要使用的标头的标题。 Otherwise, you aren't strictly guaranteed that they'll be initialized before main begins. 否则,您不能完全保证在main开始之前将它们初始化。

in TypeOne.h 在TypeOne.h中

#include "master.h"

class TypeOne { 
    static std::unique_ptr<TypeOne> Create();
    //stuff
};
static const auto TypeOneInitialized = Activators[0] = &TypeOne::Create;

If you have a cpp who shouldn't depend on TypeTwo, simply don't include it's header. 如果您有一个不应该依赖TypeTwo的cpp,只需不包含它的标头即可。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM