Pergunta

Qual é a melhor maneira de ter um membro estático em uma classe de biblioteca não modelada, sem colocar o ônus de definir o membro no usuário da classe?

Digamos que eu queira fornecer esta classe:

class i_want_a_static_member
{
    static expensive_resource static_resource_;

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

Então o usuário da classe não deve esquecer de definir o membro estático em algum lugar (como já respondidas muitos vezes):

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

Eu tenho uma resposta abaixo, mas ela tem algumas desvantagens.Existem soluções melhores e/ou mais elegantes?

Foi útil?

Solução

C++17 e superior

Usar inline static variáveis ​​para inicialização não dinâmica:

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

E use variáveis ​​estáticas locais de função caso contrário:

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

C++14 e abaixo

Use estática local de função, pois elas são mais fáceis de usar.

Se por algum motivo você realmente deseja uma estática membro de dados, então você pode usar o truque do modelo:

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

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

Na estática local

Para recursos que requerem inicialização dinâmica, é melhor usar uma estática local.

A ordem na qual as estáticas do escopo de arquivo ou de classe são inicializadas dinamicamente é indefinida, em geral, levando ao fiasco da ordem de inicialização estática quando você tenta ler uma estática não inicializada como parte da inicialização de outra.A estática local resolve o problema sendo inicializada lentamente, no primeiro uso.

No entanto, há uma pequena sobrecarga no uso da estática local.Do C++ 11 em diante, a inicialização deve ser thread-safe, o que normalmente significa que qualquer acesso é controlado por uma leitura atômica e uma ramificação bem prevista.

Outras dicas

Minha própria solução é usar uma classe de suporte modelada, já que membros estáticos funcionam bem em modelos, e usar esse suporte como classe base.

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

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

Agora use a classe titular:

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

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

Mas como o nome do membro é especificado na classe titular, você não pode usar o mesmo titular para mais de um membro estático.

A partir do C++ 17.Agora você pode usar variáveis ​​inline para fazer isso:

static const inline float foo = 1.25f;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top