You are using “indirect reference in the general sense” in your C++ programming. There’s nothing wrong with that. It is almost as powerful as programming with pointers and reference (in the C++ language).
Although, there is one technicality pitfall in the way you use
For software safety sake, I’ll describe that technical pitfall first. It’s more important to know about that pitfall, than to have your main question answered.
When objects are placed into a vector, the vector contains a copy of the object. These objects have addresses, from which you can create references (in the C++ sense). These addresses are stable until the next time you cause the vector to reallocate (growing, clearing), or causing the items to shift (e.g. delete an item in the middle). If you keep using addresses that are no longer valid (called pointer invalidation), it can trigger “undefined behavior” (UB). Once UB happens, anything can follow – the correctness of subsequent operation is no longer a guarantee.
In order to safely allow individual items in a C++ collection to be allocated (added) and deallocated (removed), these items will have to be allocated in the heap.
Here, the “heap” refers to the actual heap, i.e. the dynamic memory allocation system in C++. The dynamic memory allocation system allows individual allocations to be requested and relinquished.
Your programming style, which allows you to pre-allocate your
vectors up-front, is comparable to the static memory allocation style (on a semantic level).
Static memory allocation style was the norm several decades ago, and is still mandated for certain safety critical systems, such as vehicle electronic control systems for the powerchain and fluidics parts, certain aircraft avionics systems, and weapons systems. However, it is less powerful than dynamic memory allocation style, since static memory allocation style puts a limit on what can be implemented. That said, for applications with well-defined, non-extensible scope (e.g. controlling a specific aspect of a mechanical system, and nothing else, not having to interface with anything else), it is possible to stay with static memory allocation style.
Some of the examples you mentioned are examples of “handle body idiom” (link).
In C++, a handle class allows its users to normally use C++ copy semantics to achieve something similar to C++ pointers and references.
Mat class is a “handle” class. To illustrate this, consider this code snippet:
cv::Mat matOne(cv::Size(640, 480), CV_8UC3); cv::Mat matTwo = matOne;
After these two lines of code,
matOne both reference the same object (the matrix or image). This is due to the design and the implementation detail of the
If you want to implement a class that behaves similarly, you will need to learn about C++ pointers and references, i.e. the knowledge that you’re curious about and felt like missing.
A bit on the “linguistics” of the word “semantics”.
In C++, the phrases “copy semantics” and “reference semantics” both refer to aspects of the C++ syntax and its usage. Thus, the use of the word “semantics” is a misnomer, when judged by the standard of the English language.