从零开始独立的TU构建静态数据结构

时间:2015-12-12 14:37:00

标签: c++ c++11 thread-safety instantiation static-initialization

我有几个独立编写的翻译单位;为了便于讨论,每个都有一个(静态或外部)全局std :: string变量。这些字符串可能具有不同的名称,与TU的名称无关。并且我不保证编译的TU在与具有main.cpp功能的TU(例如,magic1.h)链接之前才会联系。它们都包含相同的标题fun_strings,它定义了一个名为#include <string> #include "magic1.h" int main() { // magic2 for(const std::string& s : fun_strings) { foo(s); } } 的全局变量,我们将在稍后选择它的类型。

现在,我希望能够做到以下几点:

main.cpp

关键在于即使foo.cpp _doesn't_include_any_of_the_other_TUs_,它们也有一些静态代码,这会导致fun_strings拥有所有TU各个字符串的副本/引用/指针。

当然,问题是如何实现这一目标。我将“magic1”和“magic2”表示为可以放置常用代码的地方。对于带有字符串的示例TU,请在std::string just_a_string("I'm a foo fun string");中使用{{1}}。

备注:

  • 解决方案必须是线程安全的,尽管我猜这应该不是问题。
  • 这是我实际上要做的事情的一个简化版本,所以对动机的道歉有点模糊。
  • 忽略碰撞的可能性,在我遇到的实际问题中,不能有任何碰撞。
  • 我宁愿不做任何基于动态加载对象和遍历其符号表的事情(如果我使用静态方法失败,那就是我可能会做的事情)

1 个答案:

答案 0 :(得分:2)

如何创建一个在声明字符串时自动将字符串添加到fun_strings的类:

class fun_string
{
public:
    fun_string(const char * string)
        : m_string(string)
    {
        get_fun_strings().push_back(m_string);
    }
private:
    string m_string;
};

在翻译单元中,您将使用fun_string定义全局字符串。

在上面的代码中,我直接使用了get_fun_strings()而不是全局名为fun_strings的代码。这是为了避免在初始化另一个静态变量时使用静态变量时可能出现的任何static initialisation fiasco问题。

vector<string> & get_fun_strings()
{
    static vector<string> v;
    return v;
}

请注意,从C ++ 11开始,本地函数静态保证以线程安全的方式初始化。这可能不是一个问题,因为如果你有至少一个全局fun_string,函数local static将在main()之前初始化,因此可能在创建任何其他线程之前。

至于忽略冲突要求 - 这可以在fun_string构造函数内完成。也就是说你应该在插入之前检查碰撞并适当地处理这种情况。

以下是此方法的live demo

有几点需要注意:

  • 正如Yakk在评论中所提到的,不要指望get_fun_strings()返回的向量包含main()之前的所有字符串。
  • 不要在静态对象的析构函数中使用get_fun_strings()。请参阅有关静态初始化顺序的页面,了解其原因以及如何更改它以支持此类用法。