lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


luaL_check* functions are designed to throw an error if the type is not the correct one, and you don't want errors to be thrown, be it with C++ exceptions or C long jumps. There is no solution to that. If you don't want exceptions and long jumps, just don't use them. You don't have to use luaL_check* functions to convert your data. Here is a non-throwing version of your SArg (I made it a macro since in your code snippet you don't pass L explictly):

#define SArg(index) (lua_isstring(L, index)?lua_tostring(L, index):"")

I have troubles understanding why so much has been written around a problem that is so easy to solve.

-----Message d'origine-----
De : lua-bounces@bazar2.conectiva.com.br [mailto:lua-bounces@bazar2.conectiva.com.br] De la part de Glenn Maynard
Envoyé : 16 octobre 2006 15:48
À : lua@bazar2.conectiva.com.br
Objet : Re: Lua error handling and C++

On Mon, Oct 16, 2006 at 02:21:19PM -0500, Rici Lake wrote:
> That would be the suggestion if you were using a C++ program with 
> exceptions. If you're not, then Lua error handling with C++ is no 
> different than Lua error handling with C: to wit, if you acquire 
> resources and then use a Lua API which might throw a Lua error, you 
> must use lua_pcall or lua_cpcall in order to trap the error so that 
> you can release the resources. (Alternatively, you can make sure that 
> the resources are part of a Lua userdata with an appropriate __gc
> metamethod.)

An actual binding:

        static int SetSongOptions( T* p, lua_State *L )
        {
                ModsLevel m = Enum::Check<ModsLevel>( L, 1 );

                SongOptions so;

                so.FromString( SArg(2) );
                p->m_SongOptions.Assign( m, so );
                return 0;
        }

SArg(2) is shorthand for "lua_checkstring(L, 2), and convert to a std::string".
It might error; if that happens, SongOptions will leak.

I could write it like this (which may also not be portable, but is definitely better):

        static int SetSongOptions( T* p, lua_State *L )
        {
                ModsLevel m = Enum::Check<ModsLevel>( L, 1 );
                size_t iOptionsSize;
                const char *pOptions = luaL_checklstring( L, 2, &iOptionsSize );

                // everything that might trip Lua errors above; all C++
                // ctors below
                std::string sOptions( pOptions, iOptionsSize );
                SongOptions so;

                so.FromString( sOptions );
                p->m_SongOptions.Assign( m, so );
                return 0;
        }

but this is cumbersome here and worse in the general case (we have helpers like SArg for a reason: there are lots of them).  It's also hard to know if it's correct; there's no way to get a compiler warning if it's wrong.

I suppose I could try something like this:

        static int SetSongOptions( T* p, lua_State *L )
        {
                ModsLevel m = Enum::Check<ModsLevel>( L, 1 );
                luaL_checkstring( L, 2 );

                // ...

                so.FromString( SArg(2) );
         }

where SArg is unlikely to error, since it checked the type and did any string conversion already.  But this is just working around one source of errors; errors detected during less trivial traversals are harder to check in advance.  (Like the above, it's also hard to check for correctness.
Since they would be problems that would compile silently, manifest as small memory leaks, and only happen as a result of uncommon Lua errors, this would be a persistant source of small, hard to fix code errors.)

(As an aside, I'm not worried about OOM errors; popping up a dialog and dying is acceptable here.  It's the other more common, less fatal errors that would be nice to handle properly.)

--
Glenn Maynard