2009-04-23 27 views
11

Tengo un miembro de la clase estática que es un poco de contenedor, comoLlenar un recipiente miembro estático en C++

(foo.h)

class Foo 
{ 
    ... 
private: 
    static list<string> s_List; 
} 

que necesito para llenar la lista con un número de valores específicos En realidad, debería ser también const, pero que podría complicar aún más el problema. Todas las funciones miembro de clase son estáticos, por lo que la inicialización en un constructor no tiene sentido.

Respuesta

15

una solución común es hacer algo como esto:

// header 
class Foo 
{ 
... 
private: 
    static list<string> s_List; 
} 

// cpp 
list<string> init() 
{ 
    list<string> tmp; 
    ... fill tmp with strings 

    return tmp; 
} 

list<string> Foo::s_List(init()); 

el otro método es como Neil Butterworth sugirió.

+1

Supongo que la suya es una solución más versátil, porque un miembro privado se puede inicializar sin ningún problema ... ¿y es posible que s_List sea const? Entonces init() debería devolver const list también. ¿Derecha? – Maleev

+0

Asimismo, desde el punto de vista del rendimiento: ¿no sería mejor volver una referencia a tmp, porque será coppied todos modos por el constructor de copia implícita (o operador de asignación, corríjanme) en la última línea? Entonces no lo coppied dos veces. Cualquier sutileza que no conté? – Maleev

+0

sí, podría cambiarlo a una lista de const <>. sin embargo, no puede devolver una referencia ya que "tmp" es una variable local y morirá una vez que salga de init(). –

0

Las formas en vano yo (el autor de la pregunta) hemos tratado de hacer esto.


he intentado hacer algo bajo como (en foo.cpp):

list<string> Foo::s_List = list<string>(); 
Foo::s_List.insert("apple"); 
Foo::s_List.insert("bannana"); 
Foo::s_List.insert("grapes"); 

Pero eso da un error de compilación.


entonces pensé en hacer un método initialize() y llamar a las cosas bien desde el código

void Foo::Initialize() 
{ 
    s_List.insert("rats"); 
    s_List.insert("cats"); 
} 

Foo::Initialize(); 

// error: compilador considera que es un redefenition del método, no una llamada.


La única idea viable que queda (havent probado todavía) sería comprobar si la lista está vacía en cada método que utiliza, y si es el caso, llamar a Initialize(). ¡Pero eso es feo!

+0

Inicializar debería ser una función estática. Disculpe la pregunta, pero ¿está tratando de hacer llamadas de función * fuera * de funciones o métodos? – Emiliano

+0

Sí, de hecho yo era :) – Maleev

0

una posible solución sería utilizar un método de acceso que comprueba para ver si se inicializa, y lo hace si no lo es.

8

Otra alternativa es crear una clase simple initialiser:

list <string> Foo::s_List; 

struct Init { 
    Init() { 
     Foo::s_List.insert("apple"); 
     Foo::s_List.insert("bannana"); 
     Foo::s_List.insert("grapes"); 
    } 
}; 

static Init doInit; 

Tenga en cuenta que, ya que la lista es privada, esto probablemente será necesario que para hacer Init un amigo de Foo. A menudo también es conveniente hacer que dichas clases estén contenidas en la clase que están inicializando.

Sin embargo, acabo de volver a leer su pregunta y ocurre otra idea: si la lista es const, presumiblemente no la cambiará, en cuyo caso una simple matriz de cadenas, inicializada con las cadenas en orden ordenado puede ser una mejor solución. Sin duda será más rápido para buscar (usando std :: binary_search) que una lista, y por supuesto puede ser inicializado con facilidad.

+0

1, se me adelantó :) –

+2

Buena idea. Está garantizado que funciona, porque los miembros estáticos y globales se inicializan en orden en cada archivo fuente. Como la lista es privada en la pregunta original, necesitará una declaración de amigo. –

+0

Se ve genial. Gracias – Maleev

1

Depende de los valores que se necesita para poner en esa lista. ¿Están estáticos o requieren algún tipo de cálculo?

Si son estáticos, se puede hacer esto:

namespace { 
    const char* const initVals[] = { "A", "B", "C" }; 
} 

list<string> Foo::s_list(initVals, initVals + 3); 
4

Si su compilador soporta C++ 0x, esto es realmente trivial de lograr.

#include <iostream> 
#include <list> 

class Foo 
{ 
public: 
    static std::list<std::string> s_List; 
}; 

std::list<std::string> Foo::s_List = {"hello", "world", "asdf", "qwerty"}; 

int main() 
{ 
    for(const std::string& str : Foo::s_List) 
     std::cout << str << std::endl; 

    return 0; 
} 

Esto funciona para miembros estáticos const y non-const. Probé este fragmento con clang-4.2, gcc-4.7, gcc-4.6 y gcc-4.5. Gcc-4.5 no es compatible con la versión actualizada de sintaxis, por lo que tendría que utilizar un bucle tradicional para con iteradores. Además, no olvide pasar el indicador -std = C++ 0x al compilador. Estoy razonablemente seguro de que Visual Studio también lo admite, pero no estoy seguro y no sé qué versiones.

Cuestiones relacionadas