Awesome
trackable_ptr
Trackable pointer. When trackable object moved/destroyed, trackers updated with new object's pointer.
Allow to have stable pointer on any movable object (in single-threaded environment). Like:
struct Data{
int x,y,z;
};
std::vector< trackable<Data> > list1;
list1.emplace_back();
trackable_ptr<Data> data {list1.back()}; // store pointer to element
list1.emplace_back();
list1.emplace_back();
list1.emplace_back();
list1.emplace_back();
// list 1 now uses another memory chuck. All pointers/iterators invalidated.
// data still alive and accessible;
std::cout << data->x;
Does not increase object lifetime (like shared_ptr
)
Also, kinda replacement for weak_ptr
in terms of object aliveness track. Dead elements have nullptr trackable_ptr
's.
Interaction with std::vector
#include <vector>
#include <iostream>
#include "trackable_ptr_extensions.h"
struct Data{
int value;
Data(int value) :value(value) {}
};
int main() {
std::vector<trackable<Data>> vec;
// fill
trackable<Data>& d1 = vec.emplace_back(1);
trackable_ptr<Data> p_i1{d1};
trackable_ptr<Data> p_i2{vec.emplace_back(2)};
// erase
vec.erase(get_iterator(vec, p_i1));
// insert
trackable_ptr<Data> p_i3 = *vec.insert(get_iterator(vec, p_i2), 3);
std::cout << "dead " << !p_i1 << std::endl;
std::cout << p_i2->value << std::endl;
std::cout << p_i3->value << std::endl;
return 0;
}
get_iterator
/ get_index
allow you to get iterator / index from trackable_ptr
. And in this way have "non-invalidatable iterators" for std::vector
.
trackable
trackable
is basically:
template<class T>
struct trackable : trackable_base, T {}
So you can access trackable<T>
the same way as T
. And if you need exactly class T, you can just cast to it. This have some drawbacks... So if you have a better idea, fill an issue.
Inheriting trackable_base
Instead of wrapping your class with trackable
, like trackable<MyClass>
; you may inerit trackable_base
, instead:
struct MyClass : trackable_base{}
std::vector<MyClass> vec;
trackable_ptr<MyClass> first = {vec.emplace_back()};
trackable_wrapper<T>
trackable_wrapper<T>
is a simple helper class:
template<class T>
struct trackable_wrapper : trackable_base{
T value;
}
Useful for cases when you can't inherit T
, or don't want to use trackable
.
Usage:
trackable_wrapper<int> i;
i.value = 100;
trackable_ptr< trackable_wrapper<int> > p_i = {i};
std::cout << p_i->value;
Overhead
-
1 ptr for
trackable
-
3 ptr for
trackable_ptr
-
O(n) complexity for moving/destroying
trackable
. Where n =tracker_ptr
s pertrackable
.