[Date Prev][Date Next][Thread Prev][Thread Next]
- Subject: Re: Avoiding string duplication
- From: Andrew Gierth <andrew@...>
- Date: Tue, 05 Nov 2019 16:52:45 +0000
>>>>> "Chris" == Chris Smith <email@example.com> writes:
Chris> Hi all,
Chris> I’m trying to understand a bit better the handling of strings in
Chris> Lua with respect to memory allocation and what is safe or unsafe
Chris> when using the C API. The context for this is that I’m dealing
Chris> with some (constant) strings that are used by both C and Lua
Chris> code, and I’d like to avoid unnecessary memory allocations.
Chris> If I push a string value onto the stack (e.g. lua_getglobal(L,
Chris> “my_string”) ) does Lua duplicate the string or just use a
Chris> reference to the original string?
If you push a string value _that you obtained from Lua_ onto the stack,
there is no copying, the stack value is just a reference. Remember also
that strings in Lua are immutable.
Where the copying happens is if you push a string onto the stack via a
C pointer, i.e. lua_pushstring. (Lua has some shortcuts to try and
detect whether it already has a copy of the same string, but it does
take some work to check this.)
Chris> If I call lua_tostring (assuming the object is an actual string
Chris> and not converted from a different type) does Lua return a
Chris> pointer to the original string content or does it duplicate the
Chris> string in a C-compatible manner and return a pointer to that?
If you call lua_tostring on a stack slot that contains a string rather
than a number, then what you get is a pointer to Lua's own existing copy
of the string (which already has a null terminator to ensure it's valid
to C). No copying is done.
Chris> Given the above and assuming that I have a Lua global string
Chris> “my_string” that is constant for the lifetime of the lua_State,
Chris> is the following code safe or not?
Chris> const char *str = luaL_checkstring(L, -1);
Chris> lua_pop(L, 1);
Chris> return str;
This is safe as long as you know that there is some reference to the
string remaining in addition to the one you popped off the stack.
If you don't know that there's another reference, then you should assume
that the char* becomes invalid as soon as you pop the stack.
BTW the global table is probably not the best place for this sort of
thing (too easy to modify, or run into collisions with other code);
maybe the registry (or a table hung off the registry) would be a better