views:

210

answers:

3

Hello!

I'm writing a C++/OOP wrapper for Lua. My code is:

class LuaState
{
     boost::shared_ptr<lua_State> L;

     LuaState(): L( luaL_newstate(), LuaState::CustomDeleter )
     {
     }
}

The problem is lua_State is incomplete type and shared_ptr constructor requires complete type. And I need safe pointer sharing. (Funny thing boost docs say most functions do not require complete type, but constructor requires, so there is no way of using it. http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm)

Can can I solve this? Thank you.

+3  A: 

You are using your own deleter, which means that you don't have to have a complete type upon construction. The only requirement is that CustomDeleter can handle that. (it may convert the pointer passed to a complete type, for example (say, from void* to CompleteType*).

The background of completeness is that once the constructor of shared_ptr is called with the default deleter, it will instantiate a class that contains the line delete p; - and for this code to be correct, p must not be incomplete. The destructor will call this deleter code indirectly, so it doesn't depend on the completeness of the type.

However if you pass your own deleter, the requirements of your own deleter will apply. Be sure to define CustomDeleter after lua_State has become completed.

Johannes Schaub - litb
Thank you for feedback. Your code is exactly what I wrote. It fails in "shared_ptr::checked_delete" at static check "typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];"
topright
@topright, if you use your own deleter that does it right, it shouldn't fail like that. Be sure to define your `CustomDeleter` in such a way that its body occurs after the definition of `lua_State`.
Johannes Schaub - litb
Oh, it works now. Thanks!
topright
A: 

It seemed strange that boost::shared_ptr would require a complete type for instantiation, so I wrote this small little test that demonstrate the opposite (code at the end).

I believe that the problem is not with the type needing to be complete, but with the second argument that you are passing to the shared_ptr constructor, that looks like a member function. The second argument must be something callable with a single pointer argument. If you want to use a member function of your wrapper you can use boost::bind to adapt the interface.

Maybe you meant?:

 LuaState(): L( luaL_newstate(), boost::bind(LuaState::CustomDeleter,this,_1) )
 {
 }

Demonstration that boost::shared_ptr does not require complete types:

// forward declarations
struct test;
test * create();
void destroy(test *);

// wrapper equivalent to the one in the question
struct wrapper {
   boost::shared_ptr<test> sp;
   wrapper() : sp( create(), destroy ) {}
};

// actual definitions
struct test {};
test * create() { return new test; }
void destroy(test *t) { delete t; }

// make it executable
int main() {
   test t;
}
David Rodríguez - dribeas
A: 

Given that a lua_State* can't be cloned, is copying a LuaState object meaningful? What are the expected semantics of copying such an inherently uncopyable object?

The behaviour you seem to want is shallow copying - and the best way to do that is for LuaState to be uncopyable and manage the lifetime of the lua_State then you can pass around the state as a shared_ptr<LuaState>.

Joe Gauterin