Vector of pointers to possibly nonexistent objects - c++

I have an object A, that I want to wrap with a list of objects (pointers to objects) of type B, that A should process.
The problem is, that some of B objects can be deleted and A doesn't know about it. I know I can handle it with exceptions, but I would rather to avoid it.
Full problem: I'm writing C++ SFML project, I want to wrap a sf::RenderWindow with a vector of sf::Drawable * pointers to objects, that window should draw. And problem is the same. Some of sf::Drawable objects may be already deleted, but sf::RenderWindow tries to use it.
I can possibly cancel the idea of wrapping, but if there a good design solution, it would be great.

You can use a std::unique_ptr which will return true or false in an if() statement depending if it has been deleted or not:
// use a std::unique_ptr that will record if its target has been deleted
std::vector<std::unique_ptr<sf::Drawable>> drawables;
// deleting an element
for(auto& drawable: drawables)
{
if(needs_to_be_deleted(drawable.get()))
drawable.reset(); // deletes object
}
// process elements
for(auto& drawable: drawables)
{
if(drawable) // returns false if element is deleted
{
// pass by reference or pointer (using get())
do_something_with_drawable(drawable.get());
}
}

You have to ensure memory is not reused, as it will result in undefined behavior if the object is no longer live when you use it.
Create a map for the live objects, and only use value, if it is still in the map

Related

Can the [this] pointer captured by a lambda be invalidated before the lambda runs?

Suppose that we have a STL container with some objects, and these objects can post functions to a queue to be executed later. But before these functions get executed, the container gets modified in such a way that pointers pointing to that object are invalidated. Let me illustrate with an example:
#include <vector>
#include <functional>
class Class_A
{
public:
std::function<void()> getFunctionToRunLater()
{
return [this] () { somethingToDo(); moreThingsToDo(); };
// Returns a lambda function that captures the this pointer,
// so it can access the object's methods and variables.
}
void somethingToDo();
void moreThingsToDo();
}
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
pendingFunction();
}
Everything fine, right? We get a function the object wants to run and, after some logic, we execute that function. This represents posting functions to a queue and them execute all functions in the queue. But now look at this one:
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
vec.reserve(1000);
// This will surely reallocate the vector, invalidating all pointers.
pendingFunction();
// And now my program is going straight down to hell, right?
}
Is my assumption correct? What will happen if the lambda doesn't capture anything at all, will the program still be logically broken? And what about if the lambda doesn't capture the this pointer, but rather some other class field specifically?
The existing answer already mentions that the pointer can be invalidated. One way to avoid the problem is, as already mentioned, changing the ownership of *this by either shared_ptr, unique_ptr or a copy. However, this comes at extra cost (dynamic allocation or extra copy) and sometimes is simply not possible (non-copyable types).
Instead, I would suggest a design that doesn't lead to this problem in the first place, i.e. not making the this pointer part of the lambda's state. Take the object as a parameter:
std::function<void(Class_A&)> getFunctionToRunLater()
{
return [] (Class_A& obj) { obj.somethingToDo(); obj.moreThingsToDo(); };
}
If copying the object is a possibility, then you can capture *this by value: (requires C++17)
return [*this] { somethingToDo(); moreThingsToDo(); }
This copies the whole object into the closure to avoid out-of-lifetime access to the original object.
Yes this program is likely to have problems. C++ does not protect you from invalidating pointers, and as you've highlighted the objects in your vector will potentially move address when the vector resizes, which will cause problems if you try to run your lambda.
You will probably be unable to compile the program without capturing this. You will also end up with issues if you try to capture references or pointers to any part of your object without being sure the memory being pointed at will not move.
It pays to be cautious, as a program like this is not guaranteed to crash even if you have a bug, as the old data may still exist in memory even when your vector resizes. So if you try capturing this and don't see any issues at runtime it does not mean that your program is correct.
For a straight forward solution, I'd look at allocating your objects on the heap using one of the smart pointer types such as std::unique_ptr or std::shared_ptr.

Non owning reference to deleteable object

What would the best practice to hold a non owning reference to a object, that can be deleted?
The first part is fairly simple, I simply using the stupid-smart pointer: observer_ptr. However, the last part makes it somewhat more difficult.
Example
Having this setup, to illustrate the need of my vector unique ptr
class Object
{
};
class Derrived : public Object
{
};
With the implementation of
vector<nonstd::observer_ptr<Object>> _observers;
vector<unique_ptr<Object>> _objects;
auto t = make_unique<Derrived>();
_observers.push_back(nonstd::make_observer(t.get()));
_objects.push_back(move(t));
// Same objects
cout << (_observers.at(0).get() == _objects.at(0).get()) << endl;
Issue
Now at any time, somewhere, one of the objects in _objects might be deleted.
I will simply illustrate this by deleting the first object in the vector:
_objects.erase(_objects.begin());
This will result in the _objects vector is empty. However, the _observers vector now points to a freed memory space.
Of course, I can simply delete the observer from _observers, but imagine having such observing references in different parts of my program.
Would there be any cleaner solution for this, and it this the right way to observe different objects?
Please let me know if the example at hand does not illustrate the problem (or any problem for that matter) that I described.
Your use-case sounds like a std::weak_ptr<Object> would be suitable non-owning representation. Of course, for a std::weak_ptr<T> the owning representation is std::shared_ptr<T>. However, since you’ll need to “pin” the object before you could access a std::weak_ptr<T> you’d have more than one owner anyway while accessing the pointer.
As stated in the comments, this is a typical use-case for std::weak_ptr:
std::weak_ptr is a smart pointer that holds a non-owning ("weak")
reference to an object that is managed by std::shared_ptr. It must be
converted to std::shared_ptr in order to access the referenced object.
Example:
vector<shared_ptr<Object>> objects;
objects.push_back(make_shared<Derived>());
weak_ptr<Object> ptr{ objects.back() };
auto sh_ptr = ptr.lock(); // increase reference count if object is still alive
if(sh_ptr) { // if object was not deleted yet
sh_ptr->doStuff(); // safely access the object, as this thread holds a valid reference
}
Today there is no way to make non-owning relationship to be enforced by compiler:
1. weak_ptr could be converted to shared_ptr
2. Everything else could be deleted.
3. Wrappers around weak_ptr that would be non convertible to shared_ptr would not work also: once reference to an object is retrieved it could be deleted too.

How to delete a pointer inside a struct object when the struct object goes out of scope?

I have a struct object that contains a pointer to an object.
struct Track
{
KalmanFilter* kalmanFilter; //Kalman filter for this track
....
};
I instantiate the struct and pointer objects by
Track track;
track.kalmanFilter = new KalmanFilter(contours[contour].centroid);
....
I then check each frame if the track is still valid by
//Temporary vector to hold alive tracks
std::vector<Track> tempTracks;
for(...)
{
//If track is valid save into temp tracks
if(tracks[track].deadTime <= deadTime) tempTracks.push_back(tracks[track]);
}
//Save all temp tracks back into tracks - this removes dead tracks that were in tracks
tracks = tempTracks;
After a while the micro-controller i'm using runs out of memory, this is the only pointer in my code so i'm pretty sure the KalmanFilter pointer is not being deleted.
So far I have tried a destructor in the Track struct which causes my micro-controller to hard fault immediately.
//Destructor frees up Kalman filter memory when the Track object goes out of scope
~Track()
{
if(kalmanFilter) delete kalmanFilter;
}
and I have tried using a unique_ptr but I cannot get the code to compile, all the examples I have found instantiate the object being pointed to at the same time as instantiating the unique_ptr. In my case I don't think I can do this.
What is the correct way to handle a situation like this?
Thanks
EDIT
So based on the comments there seems to be two main points.
Allocate the memory in the constructor
I have rewritten my struct to be
struct Track
{
Track(const Point& initialPosition) : kalmanFilter(initialPosition) {}
~Track() {}
KalmanFilter kalmanFilter; //Kalman filter for this track
};
and I instantiate it by
Track track(contours[contour].centroid);
Is this correct?
Find a better way to delete the tracks
What is the best way to remove an object from a vector without messing up the indexing during the loop? Using an STL iterator?
I implemented the solution from #M.M that seems to work
tracks.erase(std::remove_if(tracks.begin(), tracks.end(), [&](Track const &t){return t.deadTime > deadTime;}));
You can use a smart pointer:
struct Track
{
std::unique_ptr<KalmanFilter> kalmanFilter;
....
};
This means that when the Track is destroyed, if the smart pointer is managing a pointer it will invoke delete on that pointer.
It could be assigned by:
track.kalmanFilter.reset(new KalmanFilter(contours[contour].centroid));
although it'd be preferable to have this done by the constructor of Track.
This change will render Track non-copyable (but still movable). This is a good thing because previously your code did not behave properly on being copied anyway, so now the compiler will catch it for you.
You will need to modify your erase-loop to stop making copies of the elements. The normal way to do this is to use vector::erase combined with std::remove_if (the latter moves the selected elements to the end, and erase erases elements off the end):
tracks.erase( std::remove_if( begin(tracks), end(tracks),
[&](Track const &t) { return t.deadTime > deadTime; } ), end(tracks) );
Required includes would be <memory> and <algorithm>.
The way you are eliminating dead tracks will cause many copies of each track to be made.
The destructor to one of your many copies will try to deallocate that memory while active copies are still using that kalman filter which can cause issues. Also, if you can't guarantee it is NULL before being assigned... could be a random pointer being deleted.
In this situation I'd use a shared pointer. But to be honest, I feel like there is a better overall structure for how you are storing/using the tracks, I'd have to think about it and know more about the implementation though.
When you do push_back() you are creating a copy of the original Track object. Both the copy and the original object point to the same memory, and both at some point get destructed resulting in a double deallocation of the same address. Following the suggestions in the comments on better code organization will help avoid such bugs.

C++ std::vector in class, function crash on returning value and size growing in foreach

I'm writing a content management system to avoid duplicates of the same loaded texture in my game engine. The following is the function for retrieving content from the previously loaded in objects or to load in a new object if none is available.
template <class T>
T* GetContent(const char* path) {
// Check if it already exists, if yes return it
for (ContentEntry& entry : m_ContentList) {
// Same Type?
if (strcmp(entry.Type, T::GetType()) == 0)
// Same Path?
if (strcmp(entry.C->GetPath(), path) == 0)
return (T*)entry.C;
}
// Since it doesn't exist, create it
ContentEntry contentEntry (
T::GetType(),
(Content*)new T(path));
// Add it to the list
m_ContentList.push_back(contentEntry);
// And Return it
return (T*)contentEntry.C;
}
And this is the struct used to store content entries and the vector they're stored in.
struct ContentEntry {
const char* Type;
Content* C;
ContentEntry(const char* type, Content* c) :
Type(type),
C(c)
{ }
~ContentEntry() {
delete C;
}
};
std::vector<ContentEntry> m_ContentList;
Whenever this function tries to return the value, the app crashes. When I change contentEntry to a pointer (updating the code around it appropriately) it returns with no problem but I have to change the entire vector to point to ContentEntry pointers and then manually delete them which I would like to avoid if possible. How could I make this function work correctly?
Additionally, when using the pointer and stepping through the foreach loop, the vector seems to grow drastically for no clear reason, how can I stop this from happening?
Edit: For now fixed the crashing problem which I'll later refine, but the vector growing out of control is still there.
Edit2: The vector growing seems to just disappear after exiting the function so I'm just gonna mark something as answer.
From the looks of it, you are deleting something which looks like a string using delete rather than delete[]. Of course, this assumes that the string was allocated in the first place. Based on your comment you try to delete a string literal which causes undefined behavior at that point.
That said, please note that you are slicing your object when you insert it into the vector and, more importantly, you don't get a deep copy of the ContentEntry members (this type is lacking a copy constructor and probably an assignment operator). Thus, after inserting the ContentEntry into your std::vector<ContentEntry> the newly allocated object is gone. Another interesting bit is that you cast your T* to a Content*. The allocate object is deleted through a pointer to Content. Thus, either the cast is unnecessary (and hopefully your type Content has a virtual destructor) or things will start going bad at that point.
// Since it doesn't exist, create it
ContentEntry contentEntry (
T::GetType(),
(Content*)new T(path));
// Add it to the list
m_ContentList.push_back(contentEntry);
// And Return it
return (T*)contentEntry.C;
Your problem is in these three lines, in combination with ContentEntry not having a copy constructor (and copy assignment).
in the first part you create a ContentEntry instance
then you push_back a copy of that instance. this copy will point to the same T instance that the original ContentEntry pointed to.
finally, the function exits, return the pointer-to-T. But at the exit, your local copy contentEntry is destroyed, which will delete the T-instance that the returned pointer points to.
In essence, you are not following the Rule of Three and are being punished for it.
You need a copy constructor for ContentEntry.

Which type of pointer to use to implement shared access to elements of a set?

In order to make the discussion clear, I'm going to describe the problem in a very general manner, i.e. I will neither provide names of real classes nor will I describe the domain/context (however, I might if it turns out to be urgent).
Imagine class A. Let this class have 2 immutable fields, for instance x and y (please, notice, that these could be potentially big objects, i.e. inefficient to copy). Additionally, let these x and y be primary fields, i.e. only they are used in the implementation of ==/!= operators as well as hash-computing function.
Since A is immutable in terms of x and y, the idea is to let multiple instances of A (say a1 and a2) which have a1.x == a2.x a1.y == a2.y (i.e. a1 == a2) to implicitly have shared access to those x and y, so that there is no unnecessary duplication.
Moreover, now imagine that there is another field in A: z, which is secondary and mutable, and serves as a sort of behavior tweak for A. By design, it is desired to make this field shared among equal instances of A too. So, if I invoke a1.setZ(...) this change will also affect a2 because their access to z is shared.
As a result, we end up with a class A which has pure value semantics, but shares its members implicitly across equal instances. AFAIK such pattern is called Flyweight or aliasing.
One more detail before we move to the question. Most classes in the project are implemented using Pimpl idiom:
private:
class Private;
Private* p;
and class A is not an exclusion. That's why the proposed idea of implementing the scheme described above is as follows.
Use shared pointer to A::Private instead of raw one in
Pimpl idiom;
Have global set of shared pointers to A::Private;
In constructor of A to check whether a shared
pointer to suitable A::Private already exists in the set
(utilizing x and y of course), and if yes, then simply set p
to it, otherwise create new instance of A::Private and store
shared pointer to it in this set, and similarly set p to it;
A::Private's destructor should remove shared pointer to this from the set.
This looks like the most straightforward and intuitive implementation. However, the problem is that since this global set holds a shared pointer to A::Private, it means that even when all instances of corresponding A are destroyed, the reference counter will stay on 1, i.e. it will never reach 0, and thus the memory is never freed.
I thought it would be good if some shared pointers would offer a method to set lower bound for the reference counter. In this case, for example, I would simply set it to 1 which would mean that when it reaches 1 it frees the memory. Unfortunately, I haven't found any implementation of such behavior in popular libraries (Boost, Qt, Poco, etc.). Of course, I could do manual reference counting for my problem, but that just doesn't feel right and smells like reinventing the wheel.
Probably, there are other ways to solve this problem. Looking forward for your suggestions.
NOTE: I would like to immediately intercept any advising to transform the problem to pointer semantics which I am well aware of. I need the solution exactly for the scheme described above.
If I understood correctly what your design issue is, then I would let the global set contain weak, non-owning pointers (e.g. weak_ptr<>) which are able to check if they are dangling, yet they do not increase the reference count.
std::vector<std::weak_ptr<Private>> _objects;
Therefore, when all owning shared pointers to an object are destroyed, the object will be destroyed as well**.
Now your global set will be left with a dangling weak_ptr<>, but the nice thing is that you can check whether that pointer points to an object which is alive or not (use the lock() member function to obtain a possibly null shared_ptr<>. And if it doesn't, you won't dereference it:
// A simple, hypothetical loop through the collection of objects
// which does something, but checks whether the pointers are
// dangling before doing that something on a possibly dead object
// that would be Undefined Behavior)
std::for_each(_objects.begin(), _objecs.end(), [] (std::weak_ptr<Private> p)
{
std::shared_ptr<Private> sp = p.lock();
if (sp != nullptr)
{
sp->callMember(); // For instance...
}
});
If you also want to remove the corresponding weak_ptr<> to an object from the collection once the object gets destroyed, then you could use a custom deleter routine. Your routine will be invoked when the object is destroyed and will be passed the pointer to that object: at this point, before deallocating, you can erase the corresponding element from the set.
For example, a function that instantiates new objects of type A and returns a shared_ptr to it could look this way:
static std::shared_ptr<object> make_A()
{
std::shared_ptr<Private> sp(
new Private(), // Instantiate the object
[] (Private* p) // Set up the custom deleter...
{
// Remove the corresponding element from the vector...
_objects.erase(
// ...so let's find that element!
std::find_if(
_objects.begin(),
_objects.end(),
[p] (std::weak_ptr<priv> wp)
{
// lock() will return a null pointer if wp is dangling
std::shared_ptr<priv> sp = wp.lock();
// In case wp is not dangling, return true if and only
// if it points to the object we're about to delete
return ((sp != nullptr) && (sp.get() == p));
})
);
});
}
Here I assumed C++11, you could easily do the same in C++03 by replacing std::shared_ptr<> with boost::shared_ptr<>, std::weak_ptr<> with boost::weak_ptr<>, and lambdas with properly-defined functors.
Hope this helps.
Have you checked Boost.Flyweight out?