-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 用のライブラリを設計するためのクリーンな方法はありますか?」

テンプレートクラスの個別のインスタンス化ごとに静的メンバー変数が1つしか作成されないため、これには静的メンバーを使用することを考えました。しかし、これにより、静的メンバーのスペースを宣言する責任があるのは誰かという問題が生じます。そうする人は、「それを初期化する正しい方法を知っている」必要があります。

 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

static members of templates won't work well across APIs if you want to ensure all instantiations of Foo<1> share the same table. This is because, going across module boundaries, if module A creates Foo<1> and module B creates Foo<1>, it will duplicate the static members.

I think your best bet is to map those integers to their corresponding tables at runtime.

I could hardcode a dependency on an assumed thread library, and build a global map that's filled on-demand. But my question is:

In the modern C++11 world, is there a clean way designing a library for Foo which does not have dependencies outside of the standard libraries?

As a practical answer, no, not yet. You need critical sections/mutual exclusion for your table if you want thread safety (unless you can manage to make a shared container that is thread safe and lock-free with no third party dependencies) and there's nothing out of the box in C++11 that's implemented yet (at least in popular compilers) to give you cross-platform concurrency AFAIK.

In the future, C++11's concurrency features will support mutexes and atomics out of the box, but popular compilers haven't implemented this feature yet to my knowledge.

于 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 がテンプレート化された foo を作成するという事実は、問題の解決には役に立ちません。少し混乱しました。これにはテンプレートは必要ありません。

// 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 に答える