Почему объект, который мой C ++ указывает, теряет свои значения в моем фабричном образце? - PullRequest
0 голосов
/ 03 февраля 2020

Я пытаюсь использовать фабричный шаблон для создания различных типов объектов "State". Объекты возвращаются с указателем (State *), но вскоре после создания объектов значения, на которые они указывают, исчезают (go в NULL или сбрасываются в логическое «true»).

Код непосредственно ниже здесь все идет не так, как надо, но ниже приведен полный пример кода, который компилируется и запускается. Кроме того, я опубликовал изображения значений отладчика до и после команды usleep ().

Мне кажется, что это может быть связано с областью видимости и сборщиком мусора, но я не эксперт по C ++ любой натяжкой. Я бы подумал, что мой указатель сохранил бы мой ссылочный объект живым.

// relevant code

        void execute(){
            // Calling the constructor directly as an example
            State directState = State("temp", false, false, false);
            // Using factory pattern to create a state.  Just creating the "default" state as an example
            State * factoryState = StateFactory::getDefaultState();
            // factoryState -> name is "Reading" in the debugger, but when I try to print it out, it's gone
            // Grab the names for easy reference
            const char * dName = directState.name;
            const char * fName = factoryState -> name;
            usleep(1000000 / 100);
            // factoryState -> name .... it's vanished?
            usleep(1000000 / 100);
            // TODO we would run the factoryState -> execute() function here
        }

// Complete code example

#include <iostream>
#include <zconf.h>

// Main generic "State" class
class State {
    public:
        const char * name;
        bool isReadable;
        bool isExecuting;
        bool isFinished;

        State(const char name[], bool isReadable, bool isExecuting, bool isFinished){
            this -> name = name;
            this -> isReadable = isReadable;
            this -> isExecuting = isExecuting;
            this -> isFinished = isFinished;
        }
};

// An inherited class.  There will be lots of these eventually
class StateReading: public State { ;
    public:
        StateReading():State((const char *)"Reading", true, false, false) {}
};

// Factory method that will create lots of the different states
// note that it will be returning a pointer to a "State" object
class StateFactory {
    public:
        static State* getDefaultState(){
            StateReading defaultState = StateReading();
            State* state = &defaultState;
            return state;
        }
};

// Runs the various "States" in a template pattern
class StateExecutor {
    public:
        State * state;

        StateExecutor(){
            StateReading stateReading = StateReading();
            state = &stateReading;
        }

        void execute(){
            // Calling the constructor directly as an example
            State directState = State("temp", false, false, false);
            // Using factory pattern to create a state.  Just creating the "default" state as an example
            State * factoryState = StateFactory::getDefaultState();
            // factoryState -> name is "Reading" in the debugger, but when I try to print it out, it's gone
            // Grab the names for easy reference
            const char * dName = directState.name;
            const char * fName = factoryState -> name;
            usleep(1000000 / 100);
            // factoryState -> name .... it's disappeard?
            usleep(1000000 / 100);
            // TODO we would run the factoryState -> execute() function here
        }
};


// The actual
void loop(StateExecutor stateExecutor) {
    // Run the "execute" function of whatever the current state is
    // The stateExecutor actually runs the state
    stateExecutor.execute();
    // Slow the loop down a little.  Just for effect
    usleep(1000000 / 100);
}

// Simple program to recreate an event loop
int main() {

    try {
        StateExecutor stateExecutor = StateExecutor();
        int count = 0;
        do {
            loop(stateExecutor);
            count++;
            // Arbitrarily break out of the loop after 100 events.
        } while(count < 100);
    }  catch (std::exception& e){
        std::cout << e.what() << '\n';
    }
}

Вот значения непосредственно после того, как фабрика их создала. Все выглядит хорошо.

Before usleep

Гах! Я вызвал usleep (), и поле имени factoryState исчезло, и значения bool вернулись к true (cout также делает это). Черные маги c!

After usleep

1 Ответ

2 голосов
/ 03 февраля 2020

Здесь:

    static State* getDefaultState(){
        StateReading defaultState = StateReading();
        State* state = &defaultState;
        return state;
    }

Вы возвращаете указатель на defaultState. Однако это состояние разрушается, когда функция возвращается. Использование этого указателя позже является неопределенным поведением. Вы можете объявить defaultState как static, хотя я бы предпочел сделать его членом c.

...