C ++ Инициализация статического стека - PullRequest
3 голосов
/ 23 апреля 2009

У меня есть несколько вопросов об инициализации статической коллекции. Вот пример, который я кодировал, который, кажется, работает:

#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;
}

Теперь, это лучший способ сделать то, что я пытаюсь сделать? По какой-то причине, когда я пытаюсь использовать ту же самую схему в своем реальном коде, вызов top () выводит на нет слова. Может ли быть причина для этого?

Если с моим примером все в порядке, возможно, я прибегну к публикации своего реального кода.


Вот реальный код:

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();

И так как я не могу заставить код со стеком работать, я выбрал это в данный момент:

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.");
}

Может кто-нибудь заметить ошибку в коде со стеком или, возможно, улучшить мой поспешно закодированный обходной путь?

Ответы [ 4 ]

1 голос
/ 10 апреля 2011

Вот один из способов сделать это:

#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;
}
1 голос
/ 23 апреля 2009

Не думаю, что код даже скомпилируется (для начала пропущено A:: из initializeNumbers()).

Я предлагаю вам опубликовать свой реальный код.

Однако, почему вы не просто инициализируете стек при первом вызове конструктора (конечно, с защитой потоков, если вы работаете в многопоточной среде).

Это, кажется, намного более чистый способ сделать что-то вроде (не проверено):

#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 голосов
/ 23 апреля 2009

Интересно, поможет ли что-нибудь в этом духе? Я все еще предпочитаю предложение Пакса, это проще, но это должно избежать ваших забот "is init".

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;

Если наследование заставляет вас задавать вопросы (что и должно быть, это не красиво), просто соберите стек в NumStack. Это потребует некоторых изменений в использовании чисел в коде:

class NumStack
{
public:
   NumStack(){
      obj.push(42);
   }
   stack<int> obj;
}; 
0 голосов
/ 23 апреля 2009

Определенно может быть причина для этого. В общем, у этого подхода есть две проблемы. Первая проблема заключается в том, что статические инициализаторы запускаются до запуска метода main в C ++. Это означает, что initializeNumbers будет запускаться раньше всего в программе. В этом ограниченном примере это не большая проблема.

Вторая проблема заключается в том, что C ++ не предоставляет никаких гарантий для заказа. Это означает, что если у вас есть более одной статически инициализированной переменной, компилятор может инициализировать их в любом порядке. Поэтому, если у вас есть зависимость от одной статической переменной в инициализаторе другого, вы столкнетесь с ошибками (и создание тонкой зависимости очень легко сделать).

Вам, вероятно, гораздо лучше здесь делать некоторую форму отложенной инициализации для сложных статических значений.

...