简体   繁体   中英

Why does the object my C++ point to lose its values in my factory pattern?

I'm trying to use a factory pattern to create different types of "State" objects. The objects are returned with a pointer (State*) but shortly after the objects are created, the values they point to disappear (go to NULL or reset to boolean "true").

The code directly below is where it goes awry, but below that is a complete code sample that compiles and runs. Additionally, I've posted pictures of the debugger values before and after the usleep() command.

I feel like it may have something to do with scope and the garbage collector, but I'm not a C++ expert by any stretch of the imagination. I would have thought my pointer would have kept my referenced object alive.

// 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';
    }
}

Here are the values directly after the factory created them. All looks good.

睡前

Gah! I called usleep() and the factoryState's name field is gone and the bools have reverted to true (cout does this as well). Black magic!

睡后

Here:

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

You return a pointer to defaultState . This state however is destroyed when the function returns. Using this pointer later is undefined behavior. You can declare defaultState as static , though i would rather make it a static member.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM