Trackable pointer. When trackable object moved/destroyed, trackable_ptrs updated with new object's location.
Allow to have stable pointer on any movable object (in single-threaded environment). Objects may be stack allocated.
Header only. You need only "include" folder.
Warning! Performance-wise it is not faster then using heap allocated objects (probably due to size grow). See benchmarks, your mileage may vary.
struct Data{
int x,y,z;
};
std::vector< unique_trackable<Data> > list1;
list1.emplace_back();
trackable_ptr<Data> ptr {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.
// ptr still alive and accessible;
std::cout << ptr->x;struct Box;
struct Corner{
explicit Corner(Box* box) : box(box) {}
trackable_ptr<Box> box;
int x = 0;
int y = 0;
};
struct Box : trackable_base {
Corner lt{this};
Corner rb{this};
};
std::vector<Box> boxes;
// Box can be moved around. Corner::box always valid.
// trackable_ptr<Box> can be stored in lambda callback.
Box& active_box = boxes[i];
on_some_event([box = trackable_ptr<Box>(&active_box)](){
if (!box) return;
std::cout << box->lt.x;
});On trackable destruction - all trackable_ptrs becomes nullptr.
On trackable move - all trackable_ptrs updates with new object location.
On trackable copy - trackable_ptrs unaffected.
Inherit this, if you want your class to be compatible with trackable_ptr.
struct MyClass : trackable_base {}
MyClass m;
trackable_ptr<MyClass> p = &m;trackable<int> i;
trackable_ptr<int> p = &i;
auto i2 = std::move(i);
assert(p.get() == i2.get());For the sake of sanity, trackable<const T> is forbidden, use const trackable<T> instead.
trackable()- construct object with default constructor, if possible.trackable(T&&)- conversion constructor.trackable(Args&&... args)- in-place construct object.trackable(trackable&& other)trackable(const trackable&)trackable& operator=(trackable&&)trackable& operator=(const trackable&)T* get()- return object pointer.const T* get() constT* operator->()const T* operator->() constT& operator*()const T& operator*() const~trackable()- update alltrackable_ptr's with new nullptr.
Same as trackable, but move-only.
Useful for use in containers. For example, it is not required for std::vector implementation to use move instead copy, when both copy and move constructor are available. Though all tested implementations currently prefer move, whenever possible.
trackable_ptr()- construct with nullptrtrackable_ptr(T*)trackable_ptr(trackable<T>*)auto* get_trackable() const- return address oftrackable, which holds object (returnget()otherwise).operator bool() const- return true if not nullptrT* get() const- return object pointer.T* operator->() constT& operator*() const~trackable_ptr()- exclude this from trackers list.
#include <vector>
#include <tower120/trackable_ptr_extensions.h>
int main() {
std::vector<trackable<int>> vec = {1, 2, 3, 4};
trackable_ptr<int> p{vec.begin()};
assert(get_iterator(vec, p) == vec.begin());
return 0;
}Work with contiguous containers only.
in_container(const Container&, const trackable_ptr<T> &)- check if trackable_ptr stored inside contiguous container.get_index(const Container&, const trackable_ptr<T>&)- return index of element in contiguous container. trackable_ptr must exists inside contiguous container.get_iterator(Container&&, const trackable_ptr<T> &)- return iterator of element in contiguous container. if trackable_ptr does not exists inside contiguous container, return end().
- 1 ptr for
trackable - 3 ptr for
trackable_ptr - O(n) complexity for moving/destroying
trackable. Where n =tracker_ptrs pertrackable - O(1) complexity for moving/destroying
trackable_ptr