Lua userdata lifetime management - c++

Im pushing a c++ object pointer to userdata from few different places in my c++ code. I would like lua to manage the lifetime of the c++ object (userdata). My problem is that now I have multiple instances of userdata pointing to the same c++ object in the lua environment. So GC will be called when each instance.
I was thinking that one solution would be to create some weak cache table in the lua registry (LUA_REGISTRYINDEX) to map object pointer to the actual userdata. Then when I push userdata to the environment I check this cache to see if the userdata has already been created and push that instance (otherwise create userdata and add to the cache). That way only one instance of the userdata exists in the environment.
Is this the best solution or am I missing something?

The correct answer is to stop doing this:
I have multiple instances of userdata pointing to the same c++ object in the lua environment
When you give an object to Lua, then Lua owns that object. If a pointer to that object finds its way back into C++, then those C++ APIs should not be able to grant ownership of that object to anywhere else. Including back to Lua again. So there shouldn't be a bunch of functions that can return points to the same object to Lua.
And if you do have a bunch of such functions, you need to re-evaluate whether Lua should have ownership of these objects, or whether it should just be able to use them. You'd be surprised how rarely you genuinely need to give ownership of objects to Lua.
If you absolutely cannot avoid transferring ownership, then this means that your ownership semantics are not strict. That is, there isn't a single system which owns an object. You share ownership of an object with several places.
In C++, that's spelled shared_ptr. Therefore, your userdata should store a shared_ptr<T> to the object being managed. The GC should destroy the shared_ptr, which will only destroy the managed T if all other instances of shared_ptrs which share ownership with it have been destroyed.

Related

How to manage resources that cannot be deep-copied in C++

I am creating a class that manages a resource that should not be "deep copied", that is, there can only ever be one instance of the underlying resource, even if multiple objects have access this same resource.
However, allowing multiple objects to access this resource is also dangerous, as one object could go out of scope, and self-destruct, which will also destroy the resource. In this case, is it reasonable to only define a move constructor (without allowing for shallow copies)? Or is there some way to support shallow copies, so that multiple objects can reference the same resource, but the resource will not be destroyed if at least one object still has access to the resource?
For context, the resource being managed is an OpenGL shader, and each object has the ID of this shader as one of it's members, which it uses to tell OpenGL to delete the shader when necessary.
I think that you are looking for std::shared_ptr or parallel solution; std::shared_ptr is used to share pointers to a single object, which is destroyed only after all of the shared pointers are cleared. Thus, while we still have a reference to the object, it remains valid.
Even if you are not looking to use shared_ptr, the idea behind it is to use a reference counter, which is shared by all objects that refer to the same resource - each time you call a constructor/copy constructor/copy-assignment, you increase the shared counter by 1, and in the destructor, you decrease it by 1, and if (and only if) it reaches 0 then you release the underlying resource.
Also, for completeness of the answer, I should add that for std::shared_ptr, there is in addition std::weak_ptr, which denotes access without shared ownership - it allows one to access a resource held by a std::shared_ptr while it is alive, but can be reset automatically if all of the std::shared_ptr that refer to the resource are destroyed. It is rare to see usage of it, but it is possible to use it, nevertheless.

Proper way to manage Lua light userdata

I have a void * to a C++ created object that I pass to Lua using lua_pushlightuserdata(). Lua can perform some actions on that light userdata by passing it to Lua CFunctions and retrieving it with lua_touserdata(). At some point in the future the C++ object is destructed by its owner (C++), memory freed, and set to null. However, Lua still has a reference to this pointer, it doesn't know that it has been destroyed.
Now my Lua functions that take in this userdata make sure the pointer is valid. But what is the best approach for informing Lua that their reference to the light userdata is no longer valid? Do I expose an IsValid(lightuserdata) function to Lua so it can query the status? Or is there a better approach that I am missing.
In my experience I found that it's easier to make Lua own the objects, and you need full userdata to hold the pointer or complete object within userdata memory area. Full userdata can have metatable with __gc metamethod, so objects would be destroyed only after the last reference is garbage-collected on Lua side.
At least don't expose raw pointers to native objects to Lua through lightuserdata, it doesn't really work for native objects lifetime management. Make it some object that is owned by Lua. In simplest case it could be a Lua object (full userdata) holding smart pointer to real native object.

Usage of member variable referencing own instance

I am currently investigating code of a C++ library which is not written by me.
The code seems to be a little bit ugly to me, but I have to admin that I am no C++ pro.
The Library has a class, lets call it ExampleClass, which has a member variable std::shared_ptr<ExampleClass> this_ec which is not set in the constructor, but seems to be set always when another object creates an instance of ExampleClass:
std::shared_ptr<ExampleClass> ec = std::make_shared<ExampleClass>(...);
ec->this_ec = ec;
Could it be that this is used to prevent garbage collection?
Could it be that this is used to prevent garbage collection?
Yes, if by "garbage collection", you mean "automatic deletion". The object won't be deleted as long as at least one shared pointer exists, so this will keep the object alive at least until that pointer is reset or reassigned.
This rather defeats the purpose of using smart pointers, since it's now easy to leak objects by losing all external pointers to them. Tread carefully here.
A less error-prone way to make a shared pointer to the current object available within the class is to inherit from enable_shared_from_this<ExampleClass>, and obtain the pointer with shared_from_this(). This effectively stores a weak pointer, which doesn't prevent deletion.

Pointers and Object Oriented Programming

How do pointers work with the concepts of Object oriented programming?
As I understand it (and please recognize, I'm classified as an ID-10T), the main tenet of OOP is containment and keeping management responsibility (memory/implementation/etc.) contained within the class; but when an object's method returns a pointers it seems like we are 'popping' the object. Now, somebody might need to worry about:
Are they supposed to delete the pointer's associated object?
But what if the class still needs the object?
Can they change the object? If so, how? (I recognize const might solve this issue)
and so forth...
It seems the user of the object now needs to know much more about how the class works and what the class expects of the user. It feels like a "cat's out of the bag" scenario which seems to slap in the face of OOP.
NOTE: I notice this is a language independent question; however, I was prompted to ask the question while working in a C++ environment.
What you describe are ownership issues. These are orthogonal (i.e. independent, you can have either without the other or even both) to object orientation. You have the same issues if you do not use OOP and juggle pointers to POD structs. You don't have the issue if you use OOP but solve it somehow. You can (try to) solve it using more OOP or in another way.
They are also orthogonal to the use of pointers (unless you nit pick and extend the definition of pointer). For example, the same issues arise if two separate places hold indices into an array and mutate, resize and ultimately delete the array.
In C++, the usual solution is to select the right smart pointer type (e.g. return a shared pointer when you wish to share the object, or a unique pointer to signify exclusive ownership), along with extensive documentation. Actually, the latter is a key ingredient in any language.
One OOP-related thing you can do to help this is encapsulation (of course, you can have encaptulation just fine without OOP). For instance, don't expose the object at all, only expose methods which query the object under the hood. Or don't expose raw pointers, only expose smart pointers.
For starters... You can't have polymorphism without pointers or
references. In C++, traditionally, objects are copied, and have (for
the most part) automatic storage duration. But copy doesn't work with
polymorphic objects—they tend to get sliced. And OO also often
means identity, which in turn means you don't want copy. So the
solution is for the object to be dynamically allocated, and to pass
around pointers. What you do with them is part of the design:
If the object is logically part of another object, then that object is
responsible for its lifetime, and objects which receive the pointer
should take steps to ensure that they don't use it after the owning
object disappears. (Note that this is true even in languages with
garbage collection. The object won't disappear as long as you've got a
pointer to it, but once the owning object is invalid, the owned object
may become invalid as well. The fact that the garbage collector won't
recycle the memory won't guarantee that the object you point to is
usable.)
If the object is a first class entity itself, rather than being
logically part of another object, then it should probably take care of
itself. Again, other objects which may hold a pointer to it must be
informed if it ceases to exist (or becomes invalid). The use of the
Observer pattern is the usual solution. Back when I started C++, there
was a fashion for "relationship management", with some sort of
management classes where you registered relationships, and which
supposedly ensured that everything worked out OK. In practice, they
either didn't work, or didn't do any more than the simple observer
pattern, and you don't hear any more of them today.
For the most part, your precise questions are part of the contract that
each class has to establish for each of its functions. For true OO
classes (entity objects), you should probably never delete them: that's
there business, not yours. But there are exceptions: if you're dealing
with transactions, for example, a deleted object cannot be rolled back,
so when an object decides to delete itself, it will usually register
this fact with the transaction manager, who will delete it as part of
the commit, once it's established that roll back won't be necessary. As
for changing the object, that's a question of the contract: in a lot of
applications, there are mapping objects, which are used to map an
external identifier of some sort to the object. With the goal, often,
of being able to modify the object.
From my understanding and experience, it generally revolves around what it is that you are trying to do as well as the language using pointers (e.g. C++ vs Objective-C).
Usually, though, in C++ terms, I've found that it's best to return either a reference to a smart pointer (such as std::shared_ptr) by reference (perhaps even const reference, depending on the situation), or simply hide the pointer in the class, and if it NEEDS to be accessed or used by something outside of it, use a getter method which either copies the pointer and returns that, or returns a reference to a pointer (granted, AFAIK ref-to-ptr is only possible in C++). If someone doesn't know that you shouldn't delete a ref-to-ptr in most situations (of course, if its deallocation is handled by the class internally), you should really think twice about whether or not they're ready to be doing C++ stuff on your team.
It's fairly common to just use public references for class members if they can be stack allocated (i.e., if they won't take up too much memory), while managing heap allocated objects internally. If you need to set the class member outside of the class, it's possible to just use a set method which takes the required value, rather than access it directly.

Visual c++ native memory management best practices

I am an old C# programmer and a C programmer (without dynamic memory allocation), but would like to learn a bit about Visual C++ programming. The question that bothers me is related to memory management in C++. In C#, garbage collector takes care of the memory management, but in C++, it is necessary that some rules are established regarding who is responsible for freeing the allocated memory. I have some typical scenarios from C#:
Object is put in a container of some kind. Who is responsible for freeing the memory. What if several classes share the same object?
Factory pattern. I like using a hierarchy of classes, where the parent class has a method for creating child objects?
Is there a way to suggest to the calling method that the returned object is in ownership of the callee/caller.
I would like to hear some good tips about this.
If you write your code correctly, you won't have to worry about this, at least not directly. There are library facilities available to you that handle memory management and other resource management for you, completely automatically, so that you don't have to.
C++ provides something far better than a garbage collector: it provides deterministic destruction of all objects, and that deterministic destruction can be used to automatically manage the lifetime of every resource, unlike garbage collection which (in many common implementations) only allows you to manage memory automatically and makes you manually manage all other resources that require deterministic cleanup.
If you dynamically allocate an object, use a smart pointer to manage its lifetime. If you don't need to share ownership, then you can use a std::unique_ptr, which allows you to transfer ownership from one owener to another. If you do need to share ownership, you can use a std::shared_ptr, which uses a reference counting technique to maintain shared ownership.
There are two important rules to keep in mind:
If you have to write delete in your C++ program, the code is almost certainly wrong. C++ provides automatic lifetime management for all resources, including memory, and you should take advantage of it. The only place delete should appear is in library code where resource-owning containers are implemented and potentially in rarer, low-level code.
Prefer to deal with objects, rather than pointers to objects, wherever possible. Wherever possible, you should avoid explicit dynamic allocation. C++ isn't like languages like C# and Java where most objects get created on the heap. It is often better in C++ to create objects on the stack (using automatic variables) and return them by value.
To answer your specific scenarios:
Object is put in a container of some kind. Who is responsible for freeing the memory. What if several classes share the same object?
You should prefer, wherever possible, to store the objects themselves in the container, not pointers to the objects. If you do for some reason need to store pointers to objects, you should use a container (e.g. a std::vector) of smart pointers. If the container has sole ownership of the dynamically allocated objects, you can use a std::vector<std::unique_ptr<T>>; if the container is going to share ownership of the objects, you can use a std::vector<std::shared_ptr<T>>.
Factory pattern. I like using a hierarchy of classes, where the parent class has a method for creating child objects?
This is no different from the previous scenario: if you have a tree, it's quite simple to use a std::vector<T> (or a std::vector<std::unique_ptr<T>> if you need dynamically allocated children) to own the children.
Is there a way to suggest to the calling method that the returned object is in ownership of the callee/caller.
If the object is solely owned by the callee (e.g. in a std::unique_ptr), then you can return that smart pointer; doing so will transfer ownership to the caller.
If there is shared ownership of the object (e.g. in a std::shared_ptr), then returning the smart pointer will make the caller one of the owners; the last owner to relinquish its ownership (by destroying or otherwise resetting its std::shared_ptr that owns the object) automatically destroys the object.
James's answer is correct. However, he doesn't mention the name of the technique that he is discussing. RAII is a very important concept for memory (and other resource) management in C++. RAII stands for Resource Acquisition Is Initialization. However, don't let the name confuse you because it's a little misleading.
Wikipedia is a good place to start reading:
RAII on Wikipedia