0

I'm writing a game engine in C++ for the first time and I need a state manager / machine. I want it to have ownership of all states.

When I started digging into how functions usually work, I found out they normally copy or move a value into the function. That seems unnecessary to me.

What I want is to create the value temporarily elsewhere, pass it to the function, and have it be constructed in the state machine's memory, so to speak, without moving or copying that value. Is this possible? And is it practical?

It would look like this:

class StateManager {
  public:
    StateManager(State state) {
      this.state = state; // Magically have this.state be the passed state, without copying or moving the constructed state. I think it's called "In place construction"?
    }
  private:
    State state;
}

void main() {
  State state(12, 8); // Create an object with some parameters
  state.initialize(); // Maybe perform a few things on it
  StateManager states(state);
}
  • `StateManager(State state)` -- Just this alone invokes the copy constructor. But in addition, the code you write is only a description of what you want to do. The compiler's optimizer may remove or eliminate the copies. See the [as-if rule](https://stackoverflow.com/questions/15718262/what-exactly-is-the-as-if-rule) – PaulMcKenzie Dec 13 '20 at 03:16
  • Give ownership of the `StateManager`'s instance of `state` to `main` and let `main` fill in the state details. Have you considered that? Have a function that returns `state` by reference back to `main`, and let `main` fill in the details, call `initialize`, etc. – PaulMcKenzie Dec 13 '20 at 04:26
  • So then I won't get to pass the parameters to the method right? Or if I want to pass an extended class I won't be able to do it? I've considered that but I don't think it's what I'm looking for. I'm guessing I should be using some sort of std reference but I just think that looks so ugly and it just feels hacky... – Noud Zandbergen Dec 13 '20 at 04:49
  • We do not know what `State` consists of. Does it have a default constructor? Why not expand the `StateManager` class to allow the user to set the state, initialize, etc.? If you did that, then things like this: `StateManager states; states.set_state(12,8).initialize()` can be possible using method chaining. – PaulMcKenzie Dec 13 '20 at 05:18
  • https://github.com/aclonegeek/SSM/tree/master/src It'll basically look like the StateManager.cpp in here. I just think it's right for the StateManager to have ownership over the objects because the states will likely never be accessed anymore once they are deleted from the StateManager. Maybe some cleanup could be done from the place the state was popped from though but I'm honestly not thinking that far ahead. It just kinda bothers me this isn't possible. – Noud Zandbergen Dec 13 '20 at 05:35

2 Answers2

2

Move is generally cheap, so avoiding it at all cost is not really needed.

You can provide interface to avoid move/copy by constructing in-place

class StateManager {
public:
    template <typename ... Ts>
    StateManager(in_place_t, Ts&&... args) : state(std::forward<Ts>(args)...){}

private:
    State state;
};

int main()
{
    StateManager states(std::in_place, 12, 8);
    // ...
}

Note: in_place_t tag is used as simple template forwarding constructor has "issue" which might intercept copy constructor (non-const StameManager&). not needed for method as emplace.

Jarod42
  • 203,559
  • 14
  • 181
  • 302
0

If you want to avoid copying, you can just pass the variable in by const reference like this:

StateManager(const State& state);

The const indicates that the value of state will not change and & just means we're passing in a memory address. (By reference, not value)

Colbsters
  • 54
  • 2
  • I don't think this will allow StateManager to then take ownership of the passed state though, or will it? – Noud Zandbergen Dec 13 '20 at 04:03
  • @NoudZandbergen no, it will not. You would have to pass the `State` by value or rvalue reference, and move the object. Otherwise, pass the `State` by pointer instead, and take ownership of the pointer. Or, have `StateManager` store the `State` reference knowing it is being owned elsewhere. Otherwise, don’t pass in the `State` at all, make the `StateManager` create its own `State` internally. – Remy Lebeau Dec 13 '20 at 05:48
  • All right. Then that settles it. What I'm asking for is not possible? There's probably a good reason for it... Anyway, if you wanna take the honor you can edit your answer to say it's not possible and I'll make it the selected answer. – Noud Zandbergen Dec 13 '20 at 05:54