So I’ve come to OF from a post-Java programming background, with garbage collection and lots of features where I basically don’t have to care (too much) about memory management. The project I’m working on could be left running for days, so I just want to check a general scenario to see if I would have to explicitly delete something in order to avoid a memory leak. Any guidance much appreciated.
Say I have a struct that has a property vector<glm::vec3> positions, and I want to update it with totally new values. If rather than
s.positions.resize(0);
for (int i = 0; i < someNumber; i++) {
// add new values
}
I instead do
s.positions = newVectorOfPositions;
Will the old value be hanging around in memory somewhere, or will that get picked up and destroyed? If it were a primitive type like a float I wouldn’t be concerned, but presumably memory has been allocated for the old set of values, so should it be a shared_ptr or unique_ptr or similar?
Is totally fine.
the vector object takes care of memory allocation, as long as the class of the values is copyable (if it is not the compiler would complain).
As a rule of thumb you only need to worry about memory management if you use the new keyword.
Notice that sometimes new is used to initialize shared_ptr or unique_ptr. In that case you can ignore the previous rule, yet it is a more recommended practice to use instead make_shared or make_unique instead, which makes it easier to spot if there is somewhere to deal with memory management.
so for if you have either:
unique_ptr<SomeClass> u = unique_ptr<SomeClass>(new SomeClass(...));
shared_ptr<SomeClass> s = shared_ptr<SomeClass>(new SomeClass(...));
use instead
unique_ptr<SomeClass> u = make_unique<SomeClass>(..);
shared_ptr<SomeClass> s = make_shared<SomeClass>(...);
There is a caveat still, be aware of circular referencing when using shared_ptr which means that you have 2 shared_ptr where each store a shared_pointer to the other, as the following.
class Something{
public:
shared_ptr<Something> other = nullptr;
};
shared_ptr<Something> A = make_shared<Something>();
shared_ptr<Something> B = make_shared<Something>();
A->other = B;
B->other = A;
It will work but you’ll be leaking memory.
Instead it should be:
class Something{
public:
void setOther(shared_ptr<Something> _other)
{
other = _other;
}
shared_ptr<Something> getOther(){
if(!other.expired()){
return other.lock();
}
return nullptr;
}
private:
weak_ptr<Something> other = nullptr;
};
shared_ptr<Something> A = make_shared<Something>();
shared_ptr<Something> B = make_shared<Something>();
A->setOther(B);
B->setOther(A);
So, if you follow this practices, the only reason to worry about memory management would be if you use the new keyword
Brilliant, thanks for that- looks like I’m (probably) fine for now then. Since you bring up pointers again- I’m mostly only using pointers in function calls when I don’t want the copy constructor to be used, i.e.
This second solution can improve class decoupling: the class that define someFunction could ignore details about typeA. But this is a general advice that may be relevant or not, depending on your actual case.