2010-03-12 15 views
8

Estoy escribiendo un contenedor C++/OOP para Lua. Mi código es:shared_ptr requiere un tipo completo; no puedo usarlo con lua_State *

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

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

El problema es lua_State es de tipo incompleto y constructor shared_ptr requiere de tipo completo. Y necesito compartir el puntero de forma segura. (Lo más divertido es que los docs dicen que la mayoría de las funciones no requieren un tipo completo, pero el constructor lo requiere, así que no hay forma de usarlo. http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm)

¿Puedo resolver esto? Gracias.

+0

¿Por qué necesita compartir con seguridad el puntero, si puedo preguntar? ¿No puedes simplemente llamar a luaL_newstate en el constructor y a lua_close en el destructor? –

+0

LuaState a, b; a = b; // lua_State en b nunca se lanzará // lua_State en a se lanzará dos veces La otra opción es clonar lua_State structure en copy constructor y operator =. Pero supongo que es una solución pesada. –

+0

No puede clonar la estructura lua_State manualmente. Te explotará en tu cara. Lo he intentado :) –

Respuesta

4

Está utilizando su propio eliminador, lo que significa que no necesita tener un tipo completo en la construcción. El único requisito es que CustomDeleter pueda manejar eso. (Se puede convertir el puntero pasado a un tipo completo, por ejemplo (por ejemplo, de void* a CompleteType*).

El fondo de completitud es que una vez que el constructor de shared_ptr se llama con el Deleter defecto, se creará una instancia de una clase que contiene la línea delete p; - y para que este código sea correcto, no debe haber p incompleta el destructor llamará a este código Deleter indirectamente, por lo que no depende de la integridad del tipo

sin embargo, si se pasa.. su propio eliminador, se aplicarán los requisitos de su propia eliminación. Asegúrese de definir CustomDeleter después de que se haya completado lua_State.

+0

Gracias por sus comentarios. Tu código es exactamente lo que escribí. Falla en "shared_ptr :: checked_delete" en la comprobación estática "typedef char type_must_be_complete [sizeof (T)? 1: -1];" –

+0

@topright, si usa su propio eliminador que lo hace bien, no debería fallar así. Asegúrese de definir su 'CustomDeleter' de tal forma que su cuerpo aparezca después de la definición de' lua_State'. –

+0

Oh, funciona ahora. ¡Gracias! –

1

Parecía extraño que boost::shared_ptr requiriera un tipo completo para creación de instancias, así que escribí esta pequeña pequeña prueba que demuestra lo contrario (código al final).

Creo que el problema no es con el tipo que necesita estar completo, sino con el segundo argumento que está pasando al constructor shared_ptr, que se parece a una función miembro. El segundo argumento debe ser algo invocable con un solo argumento de puntero. Si desea utilizar una función de miembro de su contenedor, puede usar boost::bind para adaptar la interfaz.

Tal vez significaba ?:

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

Demostración de que boost::shared_ptr no requiere tipos completos:

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

dado que una lua_State * no puede ser clonado, es la copia de un objeto LuaState significativa? ¿Cuál es la semántica esperada de copiar un objeto inherentemente imposible de copiar?

El comportamiento parece que quieres es copia superficial - y la mejor manera de hacerlo es para LuaState sea incopiable y gestionar el tiempo de vida del lua_State entonces puede pasar de todo el estado como shared_ptr<LuaState>.

Cuestiones relacionadas