title: Lua 5.2 - C++ object within an object (using lua_lightuserdata)
body: <p><strong>edit: [SOLUTION IN ANSWER 2]</strong></p>
  
  <p>I am new to LUA and am having trouble trying to do what I want. I have a C++ object that looks like this:</p>
  
  <p><strong>C++ Object definitions</strong></p>
  
  <pre><code>struct TLimit
  {
      bool   enabled;
      double value;
  
      TLimit() : enabled(false), value(0.0) {}
      ~TLimit() {}
  };
  
  class TMeaurement
  {
  public:
      TMeasurement() : meas(0.0) {}
      ~TMeasurement() {}
  
      TLimit min;
      TLimit max;
      double meas;
  };
  </code></pre>
  
  <p>I want to be able in LUA to access an object of type TMeasurement in the following form:</p>
  
  <p><strong>LUA desired use</strong></p>
  
  <pre><code>-- objmeas is an instance of TMeasurement
  objmeas.min.enabled = true
  print(objmeas.min.value);
  </code></pre>
  
  <p>...etc</p>
  
  <p>The other one thing, I do not want LUA to allocate memory for the instance of the object of type TMeasurement. That will be done in my C++ code. I have tried many different things, all unsuccessful. I will post now the last of my tries.</p>
  
  <p>In my C++ code, I have defined the following:</p>
  
  <p><strong>TLimit - Get function that will be mapped to __index</strong></p>
  
  <pre><code>#define LUA_MEAS_LIMIT    "itse.measurement.limit"
  
  extern int llim_get(lua_State* L)
  {
      TLimit*     lim = (TLimit*)lua_chekuserdata(L, 1, LUA_MEAS_LIMIT);
      std::string key = std::string(luaL_checkstring(L, 2));
  
      //-- this is only to check what is going on
      std::cout &lt;&lt; "lim.get: " &lt;&lt; key &lt;&lt; std::endl;
  
      if(key.find("enabled") == 0)
          lua_pushboolean(L, lim-&gt;enabled);
      else if(key.find("value") == 0)
          lua_pushnumber(L, lim-&gt;value);
      else
          return 0;   //-- should return some sort of error, but let me get this working first
  
      return 1;
  }
  </code></pre>
  
  <p><strong>TLimit - Set function that will be mapped to __newindex</strong></p>
  
  <pre><code>extern int llim_set(lua_State* L)
  {
      TLimit*     lim = (TLimit*)lua_chekuserdata(L, 1, LUA_MEAS_LIMIT);
      std::string key = std::string(luaL_checkstring(L, 2));
  
      //-- this is only to check what is going on
      std::cout &lt;&lt; "limit.set: " &lt;&lt; key &lt;&lt; " &lt;-" &lt;&lt; std::endl;
  
      if(key.find("enabled") == 0)
          lim-&gt;enabled = lua_toboolean(L, 3);
      else if(key.find("value") == 0)
          lim-&gt;value = lua_tonumber(L, 3);
  
      return 0;
  }
  </code></pre>
  
  <p>Now, one more functions for the TMeasurement class. (I will not provide in this example the set function for member "meas").</p>
  
  <p><strong>TMeasurement - Get function for __index</strong></p>
  
  <pre><code>#define LUA_MEASUREMENT    "itse.measurement"
  
  extern int lmeas_get(lua_State* L)
  {
      TMeasurement* test = (TMeasurement*)lua_checkuserdata(L, 1, LUA_MEASUREMENT);
      std::string   key  = std::string(luaL_checkstring(L, 2));
  
      //-- this is only to check what is going on
      std::cout &lt;&lt; "meas." &lt;&lt; key &lt;&lt; " -&gt;" &lt;&lt; std::endl;
  
      if(key.find("meas") == 0)
          lua_pushinteger(L, test-&gt;meas);
      else if(key.find("min") == 0)
      {
          lua_pushlightuserdata(L, &amp;test-&gt;min);
          luaL_getmetatable(L, LUA_MEAS_LIMIT);
          lua_setmetatable(L, -2);
      }
      else if(key.find("max") == 0)
      {
          lua_pushlightuserdata(L, &amp;test-&gt;max);
          luaL_getmetatable(L, LUA_MEAS_LIMIT);
          lua_setmetatable(L, -2);
      }
      else
          return 0;  //-- should notify of some error... when I make it work
  
      return 1;
  }
  </code></pre>
  
  <p>Now, the part in the code that creates the mettatables for these two objects:</p>
  
  <p><strong>C++ - Publish the metatables</strong></p>
  
  <p>(never mind the nsLUA::safeFunction&lt;...> bit, it is just a template function that will execute the function within the &lt; > in a "safe mode"... it will pop-up a MessaegBox when an error is encountered)</p>
  
  <pre><code>static const luaL_Reg lmeas_limit_f[] = { { NULL, NULL} };
  static const luaL_Reg lmeas_limit[] =
  {
          { "__index",    nsLUA::safeFunction&lt;llim_get&gt; },
          { "__newindex", nsLUA::safeFunction&lt;lllim_set&gt; },
          { NULL,      NULL }
  };
  //-----------------------------------------------------------------------------
  
  static const luaL_Reg lmeas_f[] =  { { NULL, NULL} };
  static const luaL_Reg lmeas[] =
  {
          { "__index", nsLUA::safeFunction&lt;lmeas_get&gt; },
          { NULL,   NULL }
  };
  //-----------------------------------------------------------------------------
  
  int luaopen_meas(lua_State* L)
  {
      //-- Create Measurement Limit Table
      luaL_newmetatable(L, LUA_MEAS_LIMIT);
      luaL_setfuncs(L, lmeas_limit, 0);
      luaL_newlib(L, lmeas_limit_f);
  
      //-- Create Measurement Table
      luaL_newmetatable(L, LUA_MEASUREMENT);
      luaL_setfuncs(L, lmeas, 0);
      luaL_newlib(L, lmeas_f);
  
      return 1;
  }
  </code></pre>
  
  <p>Finally, my main function in C++, initializes LUA, creates and instance of object TMeasurement, passes it to LUA as a global and executes a lua script. Most of this functionality is enclosed in another class named LEngine:</p>
  
  <p><strong>C++ - Main function</strong></p>
  
  <pre><code>int main(int argc, char* argv[])
  {
      if(argc &lt; 2)
          return show_help();
  
      nsLUA::LEngine eng;
  
      eng.runScript(std::string(argv[1]));
  
      return 0;
  }
  //-----------------------------------------------------------------------------
  
  int LEngine::runScript(std::string scrName)
  {
      //-- This initialices LUA engine, openlibs, etc if not already done. It also
      //   registers whatever library I tell it so by calling appropriate "luaL_requiref"
      luaInit();
  
      if(m_lua)    //-- m_lua is the lua_State*, member of LEngine, and initialized in luaInit()
      {
          LMeasurement measurement;
  
          measurement.value = 4.5;   //-- for testing purposes
  
          lua_pushlightuserdata(m_lua, &amp;tst);
          luaL_getmetatable(m_lua, LUA_MEASUREMENT);
          lua_setmetatable(m_lua, -2);
          lua_setglobal(m_lua, "step");
  
          if(luaL_loadfile(m_lua, scrName.c_str()) || lua_pcall(m_lua, 0, 0, 0))
              processLuaError();   //-- Pops-up a messagebox with the error
      }
  
      return 0;
  }
  </code></pre>
  
  <p>Now, at last the problem. Whe I execute whatever lua script, I can access step no problem, but I can only access a memebr within "min" or "max" the first time... any subsequent access gives an error.</p>
  
  <p><strong>LUA - example one</strong></p>
  
  <pre><code>print(step.meas);        -- Ok
  print(step.min.enabled); -- Ok
  print(step.min.enabled); -- Error: attempt to index field 'min' (a nil value)
  </code></pre>
  
  <p>The output generated by this script is:</p>
  
  <pre><code>                              first script line: print(step.meas);
  meas.meas -&gt;                     this comes from lmeas_get function
  4.5                              this is the actual print from lua sentence
                                second script line: print(step.min.enabled)
  meas.min -&gt;                      accessing step.min, call to function lmeas_get
  limit.get: enabled -&gt;            accessing min.enabled, call to function llim_get
  false                            actual print from script sentence
                                third script line: print(step.min.enabled)
  limit.get: min -&gt;                accessing min from limit object, call to llim_get ???????
  </code></pre>
  
  <p>So. After the first time I access the field 'min' (or 'max' for that matter), any subsequent attempts to acess it will return "attempt to access index..." error. It doesn't matter whether I access first the __index (local e = step.min.enabled) function or the __newindex function (step.min.enabled = true).</p>
  
  <p>It seems that I mess up the LUA stack the first time I access the min metatble of object step. It somehow "replaces" the "pointer to step" from a LUA_MEASUREMENT metatable to a LUA_MEAS_LIMIT... and I simply don't know why.</p>
  
  <p>Please help... what is it that I am messing up so much?</p>
  
  <p>Thank you and sorry for the long post... I just don't know how to make it shorter.</p>