Using placement new and manual call to the destructor. It ensures that
C++ objects are correctly handled when creating C++ objects through
vlc_object_create<>(), and that their destructors are correctly called
when the (C++) object is destroyed.
According to the C++ draft standard, the vlc_object_t won't get
overwritten by the placement new since (7.1) will apply to the C++
object being allocated and placement-new'ed, which triggers the default
initialization of members, and the default initialization of the
vlc_object_t member enters the (7.3) case since no constructors exists
for the structure. (It's an extern "C" structure).
To default-initialize an object of type T means:
(7.1)
If T is a (possibly cv-qualified) class type ([class]), constructors are considered.
The applicable constructors are enumerated ([over.match.ctor]), and the best one for the initializer () is chosen through overload resolution ([over.match]).
The constructor thus selected is called, with an empty argument list, to initialize the object.
(7.2)
If T is an array type, each element is default-initialized.
(7.3)
Otherwise, no initialization is performed.
--: https://eel.is/c++draft/dcl.init#general-7
However, it's not possible to use a zero-initializing placement-new
operation.
include/vlc_objects.h:109: warning: The following parameter of
vlc_object_create(vlc_object_t *p_this, size_t i_size) is not
documented: parameter 'p_this'
When running code in C++, remove the macro which is applying regardless
of the language context, and provide dedicated function overload for the
same effect. In addition, provide a dedicated wrapper avoiding cast and
size specification.
Like done by _Generic in the C version, use overloading functions to
define the correct casting behaviour depending on whether the pointer
is already a vlc_object_t or possess a vlc_object_t as ->obj.
This removes the need for listing all the objects which need a casting
case, and non-vlc_object_t objects will fail with the following error:
include/vlc_objects.h: In instantiation of ‘vlc_object_t* VLC_OBJECT(T*) [with T = {anonymous}::demux_sys_t; vlc_object_t = vlc_object_t]’:
include/vlc_objects.h:83:18: error: ‘struct {anonymous}::demux_sys_t’ has no member named ‘obj’
or, if there is a obj field which is not a vlc_object_t:
include/vlc_objects.h: In instantiation of ‘vlc_object_t* VLC_OBJECT(T*) [with T = Open(vlc_object_t*)::foo; vlc_object_t = vlc_object_t]’:
include/vlc_objects.h:83:18: error: cannot convert ‘Open(vlc_object_t*)::foo::obj*’ to ‘vlc_object_t*’ in return
83 | { return &d->obj; }
| ~~~^~~
| |
| Open(vlc_object_t*)::foo::obj*
Objects have one strong reference held by their "owner", and zero or
more weak references generated by vlc_object_hold() et al. This
provides a separate function to remove the strong reference than
vlc_object_release() to remove weak ones.
With this sole change, this is really only an annotation though.
At this point, this merely avoids iterating up the objects tree to log
messages. Effectively, the logger pointer takes the place of the libvlc
instance pointer.
Going forward, this should be usable to override logging on a sub-tree.