2009-04-23 18 views
2

Ich habe einige Fragen zur Initialisierung einer statischen Sammlung. Hier ist ein Beispiel, das ich, dass codiert scheint zu funktionieren:C++ Initialisierung eines statischen Stacks

#include <stack> 
#include <iostream> 

using namespace std; 

class A 
{ 
    private: 
     static stack<int> numbers; 

     static stack<int> initializeNumbers(); 

    public: 
     A(); 
}; 

A::A() { cout << numbers.top() << endl; } 

stack<int> A::initializeNumbers() 
{ 
    stack<int> numbers; 

    numbers.push(42); 

    return numbers; 
} 

stack<int> A::numbers = initializeNumbers(); 

int main() 
{ 
    A a; 
} 

Nun, dies ist der beste Weg, zu tun, was ich versuche zu erreichen? Aus irgendeinem Grund, wenn ich dieses exakt gleiche Schema in meinem echten Code versuche, ruft oben() Drucke Kauderwelsch. Könnte es einen Grund dafür geben?

Wenn mein Beispiel in Ordnung ist, werde ich vielleicht meinen echten Code veröffentlichen. Hier


ist der eigentliche Code:

Light.h

#ifndef LIGHT_H_ 
#define LIGHT_H_ 

#include <stack> 

#include "Vector4.h" 

class Light 
{ 
    private: 
     static stack<GLenum> availableLights; 

     static stack<GLenum> initializeAvailableLights(); 

    public: 
     GLenum lightID; 
     Vector4 ambient, diffuse, specular, position, spotDirection; 
     GLfloat constantAttenuation, linearAttenuation, quadraticAttenuation, spotExponent, spotCutoff; 

     Light( const Vector4& ambient = Vector4(0.0, 0.0, 0.0, 1.0), 
       const Vector4& diffuse = Vector4(1.0, 1.0, 1.0, 1.0), 
       const Vector4& specular = Vector4(1.0, 1.0, 1.0, 1.0), 
       const Vector4& position = Vector4(0.0, 0.0, 1.0, 0.0), 
       const Vector4& spotDirection = Vector4(0.0, 0.0, -1.0, 0.0), 
       GLfloat constantAttenuation = 1.0, 
       GLfloat linearAttenuation = 0.0, 
       GLfloat quadraticAttenuation = 0.0, 
       GLfloat spotExponent = 0.0, 
       GLfloat spotCutoff = 180.0); 

     ~Light(); 
}; 

#endif /*LIGHT_H_*/ 

Light.cpp

#include <stdexcept> // runtime_error 
#include <iostream> 

using namespace std; 

#include "Light.h" 

Light::Light( const Vector4& ambient, 
       const Vector4& diffuse, 
       const Vector4& specular, 
       const Vector4& position, 
       const Vector4& spotDirection, 
       GLfloat constantAttenuation, 
       GLfloat linearAttenuation, 
       GLfloat quadraticAttenuation, 
       GLfloat spotExponent, 
       GLfloat spotCutoff) : 

       ambient(ambient), 
       diffuse(diffuse), 
       specular(specular), 
       position(position), 
       spotDirection(spotDirection), 
       constantAttenuation(constantAttenuation), 
       linearAttenuation(linearAttenuation), 
       quadraticAttenuation(quadraticAttenuation), 
       spotExponent(spotExponent), 
       spotCutoff(spotCutoff) 
{ 
    // This prints gibberish. 
    cout << availableLights.size() << endl; 

    // The error is indeed thrown. 
    if(availableLights.empty()) 
     throw runtime_error("The are no more available light identifiers."); 
    else 
    { 
     lightID = availableLights.top(); 

     availableLights.pop(); 
    } 
} 

Light::~Light() { availableLights.push(this -> lightID); } 

stack<GLenum> Light::initializeAvailableLights() 
{ 
    stack<GLenum> availableLights; 

    availableLights.push(GL_LIGHT7); 
    availableLights.push(GL_LIGHT6); 
    availableLights.push(GL_LIGHT5); 
    availableLights.push(GL_LIGHT4); 
    availableLights.push(GL_LIGHT3); 
    availableLights.push(GL_LIGHT2); 
    availableLights.push(GL_LIGHT1); 
    availableLights.push(GL_LIGHT0); 

    return availableLights; 
} 

stack<GLenum> Light::availableLights = initializeAvailableLights(); 

Und da ich den Code nicht mit dem Stapel bekommen zu arbeiten, habe ich dafür im Moment entschieden:

Light.h

#ifndef LIGHT_H_ 
#define LIGHT_H_ 

#include <stack> 

#include "Vector4.h" 

class Light 
{ 
    private: 
     static const unsigned int LIGHTS = 9; 
     static bool availableLights[]; 
     static GLenum lights[]; 

     static GLenum getAvailableLight(); 

    public: 
     GLenum lightID; 
     Vector4 ambient, diffuse, specular, position, spotDirection; 
     GLfloat constantAttenuation, linearAttenuation, quadraticAttenuation, spotExponent, spotCutoff; 

     Light( const Vector4& ambient = Vector4(0.0, 0.0, 0.0, 1.0), 
       const Vector4& diffuse = Vector4(1.0, 1.0, 1.0, 1.0), 
       const Vector4& specular = Vector4(1.0, 1.0, 1.0, 1.0), 
       const Vector4& position = Vector4(0.0, 0.0, 1.0, 0.0), 
       const Vector4& spotDirection = Vector4(0.0, 0.0, -1.0, 0.0), 
       GLfloat constantAttenuation = 1.0, 
       GLfloat linearAttenuation = 0.0, 
       GLfloat quadraticAttenuation = 0.0, 
       GLfloat spotExponent = 0.0, 
       GLfloat spotCutoff = 180.0); 

     ~Light(); 
}; 

#endif /*LIGHT_H_*/ 

Light.cpp

#include <stdexcept> // runtime_error 

#include "Light.h" 

Light::Light( const Vector4& ambient, 
       const Vector4& diffuse, 
       const Vector4& specular, 
       const Vector4& position, 
       const Vector4& spotDirection, 
       GLfloat constantAttenuation, 
       GLfloat linearAttenuation, 
       GLfloat quadraticAttenuation, 
       GLfloat spotExponent, 
       GLfloat spotCutoff) : 

       ambient(ambient), 
       diffuse(diffuse), 
       specular(specular), 
       position(position), 
       spotDirection(spotDirection), 
       constantAttenuation(constantAttenuation), 
       linearAttenuation(linearAttenuation), 
       quadraticAttenuation(quadraticAttenuation), 
       spotExponent(spotExponent), 
       spotCutoff(spotCutoff) 
{ 
    lightID = getAvailableLight(); 
} 

Light::~Light() 
{ 
    for(unsigned int i = 0; i < LIGHTS; i++) 
     if(lights[i] == lightID) 
      availableLights[i] = true; 
} 

bool Light::availableLights[] = {true, true, true, true, true, true, true, true}; 
GLenum Light::lights[] = {GL_LIGHT0, GL_LIGHT1, GL_LIGHT2, GL_LIGHT3, GL_LIGHT4, GL_LIGHT5, GL_LIGHT6, GL_LIGHT7}; 

GLenum Light::getAvailableLight() 
{ 
    for(unsigned int i = 0; i < LIGHTS; i++) 
     if(availableLights[i]) 
     { 
      availableLights[i] = false; 

      return lights[i]; 
     } 

    throw runtime_error("The are no more available light identifiers."); 
} 

Kann jemand einen Fehler im Code mit dem Stapel entdecken, oder verbessern Sie vielleicht meine hastig kodierte Abhilfe?

+0

Warum dieses Ding nicht neu gestalten? Erstellen Sie einen LightManager, der die Lichter verwaltet. Dieser Code bricht das Prinzip der alleinigen Verantwortung, in dem Lichter nicht mehr nur Lichter sind, sondern sich selbst verwalten. Mit einem Manager Lichter können Lichter und Licht-Manager verwalten können. – GManNickG

+0

Guter Punkt! Aber selbst wenn ich die statischen Daten in eine andere Klasse verschiebe, bin ich immer noch mit diesem seltsamen Initialisierungsproblem beschäftigt. –

+0

Nun, wenn Sie es in einen LightManager verschieben, muss es nicht wirklich statisch sein, da Ihr LightManager der statische (allgemeine) Einstiegspunkt zum Verwalten von Lichtern sein wird. Das sagte, es wäre gut, dieses Problem zu verstehen. :) Lass dich einfach einen anderen Ansatz wissen. – GManNickG

Antwort

1

Ich glaube nicht, dass der Code sogar kompilieren wird (fehlt A:: von initializeNumbers() für einen Start).

Ich empfehle Ihnen, Ihren echten Code zu posten.

Doch warum initialisiert man nicht nur den Stapel auf dem ersten Konstruktoraufruf (mit Fadenschutz, wenn Sie in einer Multithread-Umgebung natürlich laufen lassen).

Das ist ein viel sauberer Weg, es zu tun, so etwas wie (nicht getestet) zu sein scheint:

#include <stack> 
#include <iostream> 
using namespace std; 
class A { 
    private: 
     static boolean isInited = false; 
     static stack<int> numbers; 
    public: 
     A(); 
}; 

A::A() { 
    if (!isInited) { 
     numbers.push(42); 
     isInited = true; 
    } 
    cout << numbers.top() << endl; } 

int main() { 
    A a; 
} 
+0

Das sollte jedoch kein Problem sein, da es nach Wert zurückgegeben wird. Die Kopie des Stapels (obwohl innezient, wenn viel größer) sollte in Ordnung sein. – JaredPar

+0

Aber ich übergebe den lokalen Stapel nach Wert und weise es sofort meinem statischen Stapel zu, also sollte der Kopierkonstruktor für meinen statischen Stapel aufgerufen werden? –

+0

Denn dann muss ich diesen hässlichen isInited Check machen. :-) Ich habe den richtigen Code gepostet. Rette mich! –

0

Es kann auf jeden Fall ein Grund dafür sein. Es gibt wirklich zwei Probleme mit diesem Ansatz im Allgemeinen. Das erste Problem besteht darin, dass statische Initialisierer vor dem Start der Hauptmethode in C++ ausgeführt werden. Dies bedeutet, dass initializeNumbers vor allem anderen im Programm ausgeführt wird. In diesem begrenzten Beispiel ist das kein großes Problem. obwohl

Das zweite Problem ist, dass C++ keine Garantie auf Bestellung liefert. Bedeutung, wenn Sie mehr als eine statisch initialisierten Variable haben, ist der Compiler frei, um sie in zu initialisieren, was auch immer, um es gefällt. Wenn Sie also eine Abhängigkeit von einer statischen Variablen in anothers initializer haben, werden Sie in Bugs laufen (und eine subtile Abhängigkeiten schaffen, ist sehr einfach zu tun).

Sie sind wahrscheinlich viel besser hier, um eine Form der verzögerten Initialisierung für komplexe statische Werte zu machen.

+0

Das Problem ist, dass ich Werte von diesem Stapel für Instanzen meiner Klasse absetzen muss. Ich kann die Initialisierung nicht verzögern! –

+0

@Scott, Sie können nicht pop, bis Ihr Objekt erstellt wird, also erstellen Sie die Einträge im Konstruktor - siehe meine Antwort. Ich habe immer noch Angst vor der Hauptinitialisierung von komplexen Objekten aus den Gründen von @Jared - ich werde immer vorziehen, sie im Konstruktor zu tun. – paxdiablo

0

Fragen Sie sich, ob Ihnen etwas in dieser Richtung helfen könnte. Ich bevorzuge immer noch Pax's Vorschlag, es ist einfacher, aber das sollte deine "init" Sorgen vermeiden.

class NumStack : public stack<int> 
{ 
public: 
    NumStack(){ 
     push(42); 
    } 
}; 

class A 
{ 
    private: 
     static NumStack numbers; 

    public: 
     A(); 
}; 

//in cpp file, do as usual for static members 
NumStack A::Numbers; 

Wenn die inheritence macht Sie quesy (was es sein sollte, es ist ziemlich aint), nur Aggregat Stapel in NumStack. Dies wird einige Änderungen an die Verwendung von Zahlen im Code erfordert aber:

class NumStack 
{ 
public: 
    NumStack(){ 
     obj.push(42); 
    } 
    stack<int> obj; 
}; 
+0

STL-Container sind nicht für Vererbung ausgelegt; Dies sollte mit Vorsicht oder (meine Präferenz) gar nicht getan werden. –

+0

Ja sicher, ich bearbeitet, um Aggregation als eine Alternative zu zeigen, aber ich dachte, die Vererbung wäre in diesem Fall in Ordnung, da die Verwendung ziemlich begrenzt ist, weil NumStack keine Mitglieder hat. – Snazzer

1

Hier ist eine Möglichkeit, es zu tun:

#include <stack> 

class C { 
    static std::stack< C* > c_stack; 
    static std::stack< C* > getCStack(); 
}; 

std::stack< C* > C::c_stack = C::getCStack(); 

std::stack< C* > C::getCStack() { 
    std::stack< C* >* c_stack = new std::stack< C* >(); 
    c_stack->push(new C()); 
    return *c_stack; 
} 
Verwandte Themen