-1

假设我有一种可以为给定整数构建的查找表:

class FooLookupTable {
    ...
public:
    FooLookupTable(int radix) { 
        ...
    }
};

然后有一个类,其模板参数是相同的整数,其构造函数初始化此查找表的成员实例:

template <int radix> class Foo {
    ...
private:
    FooLookupTable table;
public:
    Foo () : FooLookupTable (radix) {
        ...
    }
};

在我的代码中,我用各种基数值来实例化它们:

 int main() {
     ...
     Foo<1> myFoo;
     Foo<1> yourFoo;
     Foo<10> theirFoo;
     ...
 }

这有效,不会产生任何毛茸茸的线程或 API 问题。myFoo但它不会在和之间共享 1 的基数表yourFoo。我可以硬编码对假定线程库的依赖,并构建一个按需填充的全局映射。但我的问题是:

“在现代 C++11 世界中,是否有一种干净的方式为 Foo 设计一个在标准库之外没有依赖关系的库?”

我想为此使用一个静态成员,因为模板类的每个单独实例化只创建一个静态成员变量。但这提出了谁负责为静态成员声明空间的问题,而这样做的人必须“知道初始化它的正确方法”:

 FooLookupTable Foo<1>::table (1);
 FooLookupTable Foo<10>::table (10);

 int main() {
     ...
     Foo<1> myFoo;
     Foo<1> yourFoo;
     Foo<10> theirFoo;
     ...
 }

阅读有关“ C++ 静态成员初始化(内部模板乐趣) ”之类的主题似乎并没有太大希望……除非我遗漏了什么。另外,如果Foo实例本身是静态的,会发生什么?:-/

4

2 回答 2

1

如果您想确保 Foo<1> 的所有实例共享同一个表,模板的静态成员将无法在 API 中正常工作。这是因为,跨越模块边界,如果模块 A 创建 Foo<1> 而模块 B 创建 Foo<1>,它将复制静态成员。

我认为你最好的选择是在运行时将这些整数映射到它们对应的表。

我可以硬编码对假定线程库的依赖,并构建一个按需填充的全局映射。但我的问题是:

在现代 C++11 世界中,是否有一种干净的方式为 Foo 设计一个在标准库之外没有依赖关系的库?

作为一个实际的答案,不,还没有。如果你想要线程安全,你需要为你的表设置关键部分/互斥(除非你可以设法创建一个线程安全且无锁且没有第三方依赖项的共享容器)并且 C++ 中没有开箱即用的东西11 已经实现(至少在流行的编译器中)为您提供跨平台并发 AFAIK。

将来,C++11 的并发特性将支持开箱即用的互斥锁和原子,但据我所知,流行的编译器还没有实现这个特性。

于 2012-02-29T23:16:04.127 回答
1

首先,您可以根据自己的定义依赖 C++11 中的标准线程库。

然后,你应该提到你需要的名字:它是一个单例。

最后,在 C++11 中有一种方法。该语言知道线程,因此,静态变量初始化是线程安全的

template <int radix>
class Foo {
public:
     // your public stuff, no contructors

     static Foo& GetInstance()
     {
          static Foo instance(...); // thread safe accoding to C++11
          return instance;
     }

private:
     Foo(...) {
     }
}

编辑:

你在评论中提到了一些公平的观点。我希望这是一个更适合您需求的答案。实际上,FooLookup 创建模板化的 foos 对解决问题没有用处。这让我有点困惑,你不需要任何模板。

// Header file
class FooLookupTable
{
public:
    // needed to use with map
    FooLookupTable()
    { }
    FooLookupTable(int index)
    { }

    static FooLookupTable& GetLookup(int index);
};


// CPP file (no library boundary problem since this file will be linked only once)

// I fear I can't do that without using a mutex explicitely, but those are in the standards.
// You'll need a recent compiler to support them (GCC 4.5 and MSVC11)
#include <mutex> 
using namespace std;

FooLookupTable::FooLookupTable& GetLookup(int index);
{
    static map<int, FooLookupTable> _tables; // thread safe in C++11
    static mutex _m;

    // The function body isn't thread safe though, so we need to protect it.
    lock_guard<mutex> l(_m); // make sure we don't create the same one twice.

    auto it = _tables.find(index);
    if (it == _tables.end()) {
        _tables[index] = FooLookupTable(index);
        return _tables[index];
    }
    else
        return *it;
}

编辑 2

使函数线程安全。我的错。毕竟,我的第一个解决方案似乎对你更好。<mutex>如果您(在编译时)知道要为其创建查找表的基数列表,则有一个解决方案。

于 2012-02-29T23:17:11.413 回答