55

クラス ユーザーにメンバーを定義する負担をかけずに、テンプレート化されていないライブラリ クラスに静的メンバーを配置する最善の方法は何ですか?

このクラスを提供したいとします。

class i_want_a_static_member
{
    static expensive_resource static_resource_;

public:
    void foo()
    {
        static_resource_.bar();
    }
};

次に、クラスのユーザーは、静的メンバーをどこかに定義することを忘れてはなりません (すでに度も回答 されているように):

// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;

以下に答えがありますが、いくつかの欠点があります。より優れた、および/またはよりエレガントなソリューションはありますか?

4

3 に答える 3

70

C++17 以上

inline static非動的初期化に変数を使用します。

struct Foo
{
    inline static int I = 0;
};

それ以外の場合は、関数のローカル静的変数を使用します。

struct Foo
{
    static std::string& Bar()
    {
        static std::string S = compute();
        return S;
    }
};

C++14 以下

単純に使いやすいので、関数ローカル静的を使用します。

何らかの理由で静的データ メンバーが本当に必要な場合は、テンプレート トリックを使用できます。

template <typename T = void>
struct Foo
{
     static int I = 0; // inline initialization only for simple types.
};

template <typename T>
int Foo<T>::I;

ローカル統計について

動的な初期化が必要なリソースについては、ローカルの静的を使用するのが最善です。

ファイル スコープまたはクラス スコープの static が動的に初期化される順序は定義されておらず、一般に、初期化されていない static を別の初期化の一部として読み取ろうとすると、Static Initialization Order Fiasco が発生します。ローカル静的は、最初の使用時に遅延して初期化されることで問題を解決します。

ただし、ローカル スタティックを使用すると若干のオーバーヘッドが発生します。C++11 以降では、初期化はスレッドセーフである必要があります。これは通常、アトミックな読み取りと十分に予測された分岐によってアクセスが制限されることを意味します。

于 2012-07-29T16:53:43.607 に答える
18

私自身の解決策は、静的メンバーがテンプレートで正常に機能するため、テンプレート化されたホルダー クラスを使用し、このホルダーを基本クラスとして使用することです。

template <typename T>
struct static_holder
{
    static T static_resource_;
};

template <typename T>
T static_holder<T>::static_resource_;

次に、ホルダー クラスを使用します。

class expensive_resource { /*...*/ };

class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
    void foo()
    {
        static_resource_.bar();
    }
};

ただし、メンバーの名前はホルダー クラスで指定されるため、同じホルダーを複数の静的メンバーに使用することはできません。

于 2012-07-29T14:06:41.800 に答える