Documentation Index
Fetch the complete documentation index at: https://mintlify.com/geode-sdk/docs/llms.txt
Use this file to discover all available pages before exploring further.
General C++ Tips
This tutorial features some tips for GD modding and C++ programming in general.Use auto
Despite what some GD modders might tell you, using auto is perfectly fine and actually usually desirable. auto is the C++-equivalent of the let keyword in languages like JavaScript or var in C#; it makes C++ infer the type of a variable. For example:
auto can lead to unexpected behaviour due to implicit type conversions. For example:
auto by just replacing the type, as this actually calls std::string’s const char* constructor. The type of string literals is const char*, so if you want to create an std::string from a string literal, it’s usually best to avoid using auto. Of course, you could do this:
Avoid C-style casts
C++ has inherited a lot of technical debt from C, and one of these is C-style casts:static_cast, reinterpret_cast, and dynamic_cast. There are also some others like const_cast, some casting functions in the standard library like std::static_pointer_cast and std::duration_cast, and some very magical and terrifying aliases in Geode like reference_cast and as, but in general these will only be used in specific situations. For most cases, you should just use static_cast.
static_cast is what you would expect type conversion to do: it converts the value to match the requested type. This works for casting between built-in datatypes, downcasting pointers, casting between your own classes etc..
dynamic_cast is a safe version of static_cast for polymorphic classes. For example:
b will either be certainly a valid B or nullptr. dynamic_cast comes with a runtime cost though, so if you know that b will definitely be a valid B, you can use static_cast instead.
Avoid memory leaks
C++ does not have a garbage collector or any sort of memory management, so you have to be careful with handling your own memory. In general, the following tips will help:Always allocate on the stack when possible
delete everywhere, C++ will automatically free the object for you.
Use references over pointers
If you’re passing data to a function or a shared parent class to a child, use references instead of pointers. References are safer for a lot of reasons, and also don’t increment memory. However, when passing by reference, you have to make sure your class outlives the reference - for example, the following code will crash:Be aware of lifetimes
In C++, objects created on the stack live until they go out of scope, and objects created on the heap usingnew live until you call delete on them. References and pointers to the object can not extend this lifetime, so make sure that if you’re referencing an object, it has not been freed.
For example, some libraries may require you to pass pointers to objects, but you probably want to just pass pointers to stack-allocated objects (since they are automatically freed, so you don’t have to worry about calling delete)
Use CCObject-based class over normal ones
Cocos2d comes with its own handy garbage collector, and if you create something like a CCArray, its memory will be automatically freed when it’s no longer used. Be wary though that this means you have to make sure any CCArray you do actually need doesn’t get garbage-collected. Cocos2d can’t know if you’ve assigned the CCArray to a variable or class member, so either use the Ref class in Geode to ensure the object stays alive, or manually keep track of it using retain if you have to. (Ref should be used in nearly all situations though)
If you’re making your own class that inherits from CCObject (for example, a node), always make sure to call autorelease on it. This will ensure the garbage collector will clean its memory. (Unless you are working with TableViewCells. In that case, never call autorelease unless you want to experience the worst bug of all time.)
Use smart pointers over pointers
If you really do have to use pointers and the class you’re working with isn’tCCObject-based, prefer using smart pointers like shared_ptr and unique_ptr over raw pointers. Smart pointers automatically manage the memory being pointed to, and free it when it’s no longer needed.
For every call to new you have, there must exist a matching call to delete
If none of the other strategies are applicable and you have to use raw pointers, the rule of thumb for memory management there is for every call to new you have, there must be a matching call to delete. The only exception to this are global manager classes, which are never freed in lieu of being static. Also, in Cocos2d code, you will call new for all of your own node classes, but never delete; this is because Cocos2d calls delete for you when the garbage collector frees the object.