www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - GC can collect object allocated in function, despite a pointer to the

reply =?UTF-8?B?IuWyqeWAiSDmvqoi?= <mio.iwakura gmail.com> writes:
Hello, I've been interested in the D language for a few years
now, but only dabble. I have read TDPL and recently started
reading D Cookbook. On the side, I started to write a small game
in D, but ran into a problem. I would greatly appreciate any help!

My design is a simple state machine. I have a module game.states,
which includes:

interface IState{
     void handleEvents();
     void renderFrame();
}

IState *currentState;
string nextState;

void changeState(){
      if(nextState != "WaitState" && nextState != "ExitState"){
          auto newState = cast(IState)
Object.factory("game.states."~nextState);
          import std.exception;
          enforce(newState);
          currentState = &newState;
          nextState = "WaitState";
      }
}

class TitleState : IState{
      void handleEvents(){
      ...
      }

      void renderFrame(){
          ...
          }
      }
      ...
}

and the game loop is of the following form:

//init state
nextState = "TitleState";
changeState();

//game loop
while(nextState != "ExitState"){
      currentState.handleEvents();
      currentState.renderFrame();
      changeState();
}

However, it appears that the changeState function has a bug.
I believe the problem is that when changeState returns, newState
gets garbage collected, despite currentState pointing to it.
I come from a C++ background, so I am not used to garbage
collection.
Normally the changeState function would explicitly free the old
state, and allocate the new one.

Am I correct that newState is liable to be collected after
changeState returns?
Is there an easy fix?
Is my design fundamentally flawed within the context of garbage
collection?
If so, what kind of design would you recommend instead?
Aug 16 2014
next sibling parent reply "Sean Kelly" <sean invisibleduck.org> writes:
Interface and object variables are reference types--you don't
need the '*' to make them so.  By adding the extra layer of
indirection you're losing the only reference the GC can decipher
to the currentState instance.
Aug 16 2014
parent =?UTF-8?B?IuWyqeWAiSDmvqoi?= <mio.iwakura gmail.com> writes:
Thank you for the help! I just removed the unnecessary
indirection and it is working great!
I was aware that interface and object variables are reference
types, but it slipped my mind. I'm too used to the C++ way of
things still :p
On Saturday, 16 August 2014 at 22:41:45 UTC, Sean Kelly wrote:
 Interface and object variables are reference types--you don't
 need the '*' to make them so.  By adding the extra layer of
 indirection you're losing the only reference the GC can decipher
 to the currentState instance.
Aug 16 2014
prev sibling parent reply "Chris Cain" <zshazz gmail.com> writes:
On Saturday, 16 August 2014 at 22:36:51 UTC, 岩倉 澪 wrote:
 void changeState(){
      if(nextState != "WaitState" && nextState != "ExitState"){
          auto newState = cast(IState)
 Object.factory("game.states."~nextState);
          import std.exception;
          enforce(newState);
// !!!!!!!!!!!!!!!
          currentState = &newState;
// !!!!!!!!!!!!!!!
          nextState = "WaitState";
      }
 }
 However, it appears that the changeState function has a bug.
 I believe the problem is that when changeState returns, newState
 gets garbage collected, despite currentState pointing to it.
 I come from a C++ background, so I am not used to garbage
 collection.
 Normally the changeState function would explicitly free the old
 state, and allocate the new one.

 Am I correct that newState is liable to be collected after
 changeState returns?
 Is there an easy fix?
 Is my design fundamentally flawed within the context of garbage
 collection?
 If so, what kind of design would you recommend instead?
This is actually not garbage collection. &newState is making a pointer to a reference that is located on the stack (that is, when you return from that function you now have a pointer that may at any time become overwritten and made invalid.) As it turns out, interfaces/classes in D are already reference types, so you can just do something like this: IState currentState; // reference to an IState void changeState(){ if(nextState != "WaitState" && nextState != "ExitState"){ auto newState = cast(IState) Object.factory("game.states."~nextState); import std.exception; enforce(newState); currentState = newState; // changed nextState = "WaitState"; } }
Aug 16 2014
parent =?UTF-8?B?IuWyqeWAiSDmvqoi?= <mio.iwakura gmail.com> writes:
I see now, makes sense. :)

On Saturday, 16 August 2014 at 22:43:21 UTC, Chris Cain wrote:
 This is actually not garbage collection. &newState is making a
 pointer to a reference that is located on the stack (that is,
 when you return from that function
 you now have a pointer that may at any time become overwritten
 and made invalid.)
Aug 16 2014