After the appearance of smart pointers in the standard C ++ library, the problem of controlling the lifetime of the object was solved. You can create objects on the stack, then they are automatically deleted when you go out of scope, or you can use unique_ptr to create objects with exclusive ownership or shared_ptr for joint ownership. But only for shared_ptr in the standard library there is a non-possessing pointer weak_ptr, which prevents the use of an invalid pointer. For other cases, use the "old and dangerous" raw pointers.
How do language developers propose to solve this problem?
The
CppCoreGuidelines website has some interesting documents (
here and
here ).
The main message is this: I cannot implement safe non-possessing pointers without violating the zero overhead principle. Therefore, we will not implement such tools at runtime, but will try to solve the problem by static code analysis.
I disagree with this position and here are my reasons:
')
- Static analysis will not be able to catch all the problems. The authors of the articles themselves say that sometimes it will be necessary to mark some constructions as safe, leaving the question of the correctness of the code on the developer’s conscience.
- In order for static analysis to work, support from compilers is needed. When it appears - is unknown.
- Static analysis does not allow you to have weak non-possessing pointers (analogous to weak_ptr, which vanishes when an object is deleted).
- Implementing such pointers violates the zero overhead principle - this is true. But, in my opinion, this principle is also violated by shared_ptr, since has an additional ref_count object or, for example, a string with its small string optimization. In any case, the standard library provides classes with clearly described characteristics, and the programmer decides whether these classes are suitable for him or not.
In my opinion, the standard library should provide classes for all major programming scripts. The lack of pointers and hanging link access is a large and still unclosed topic in C ++. I think the standard library should provide the programmer with an optional opportunity to have such pointers.
In my
RSL project, I tried to implement such a pointer. The basic idea is not new: an object is needed, which, when destroyed, will notify the pointers about the fact of removal.
Thus, we have two classes:
- rsl :: track :: trackable is a class that notifies pointers on deletion.
- rsl :: track :: pointer is a non-possessive pointer.
When
rsl :: track :: pointer 's point to the same
rsl :: track :: trackable object, they are arranged in a doubly linked list. A pointer to the head of the list is contained in
rsl :: track :: trackable . Thus, the creation of pointers takes constant time. The size r
sl :: track :: trackable is one pointer, and
rsl :: track :: pointer - 4 pointers (a pointer to an object, two pointers to organize the list, and another one to implement polymorphic behavior). Perhaps a more optimal organization of pointers, if anyone knows, please tell.
Also, this implementation is not thread-safe, to ensure work in different threads, you will have to add std :: atomic_flag and slow down the modification of pointers.
In addition, with the advent of
allocator aware containers , it became possible to implement an
allocator that allows using
rsl :: track :: pointer with standard containers. The basic idea is that now all allocations in containers are made as an instance of the allocator stored in the container or its template copy, and we can store
rsl :: track :: trackable in the allocator and transfer it to a copy.
The
tests give examples of working with the main standard containers, including std :: array, as well as
unique_ptr .
In conclusion, I want to give another script in which
rsl :: track :: pointer will be useful. These are situations similar to
delete this . Usually this happens indirectly when a code, a functor or a signal external to the object is called. This kind of error is rare, but difficult to catch.
For such cases (and any other problems with access to the hanging link) use tools such as
google sanitizers , which allow you to catch such problems.
But these tools have their disadvantages:
- Work not everywhere (not on all platforms).
- Code instrumentation is needed - the code is different from production.
- There is no analogue of weak_ptr, the pointer that vanishes when an object is deleted.
- Detects the time and place of access by an invalid pointer. Although, as a rule, the more interesting is the moment when the removal of an object to which there are pointers occurs. For the same reason, the instrumentation detects not all cases of incorrect access, but only those that actually worked during testing.
I hope the library will be useful to C ++ developers. Perhaps there are other ways to solve such problems, I will be happy to hear in the comments.
PS Once again, for convenience, I provide a link to the
RSL code.