Much to my shame, I haven't had the chance to use smart pointers in actual development (the supervisior deems it too 'complex' and a waste of time). However, I planned to use them for my own stuff...
I have situations regarding de-initing a module after they are done, or when new data is loaded in. As I am using pointers, I find my code littered with check for null such as this...
// TODO: Reset all opened windows
// Deinit track result player
if (trackResultPlayer_)
trackResultPlayer_->reset();
// disconnect track result player
disconnect(trackResultPlayer_);
disconnect(trackResultAnimator_);
}
if (videoPlayerWindow_)
{
videoPlayerWindow_->reset();
// Disconnect the video player window from source movie data
disconnect(videoPlayerWindow_);
}
// Disconnect this module from its children as they would be connected again
disconnect(this);
If I am to use smart pointers, instead of raw pointers, how could this problem be alleviated?
Make each of your classes implement a destructor which performs all the cleanup/deinitialization you need for that class.
Create an instance of the class, and wrap it in a boost::shared_ptr.
Then pass copies of that to every function which needs access to the instance.
And the smart pointer will ensure that once the object is no longer used (when all the shared pointers have been destroyed), the object they point to is destroyed. its destructor is run, and all the cleanup is executed.
As always in C++, use RAII whenever possible.
Whenever you have code like x.reset() or disconnect(x), the first thing you should do is ask yourself "doesn't this belong in a destructor?"
Further, whenever you use x->y() you should ask yourself:
Why is this a pointer? Couldn't I make do with a single instance allocated on the stack, and perhaps a few references to it?
If it has to be a pointer, why isn't it a smart pointer?
Smart pointer are primarily an instrument to manage the memory being pointed to. They are not meant as something, which would free you from the burden of NULL value checking...
In you example code, I don't see much potential for smart pointers reducing the code complexity, unless you move calls like videoPlayerWindow_->reset(), disconnect(videoPlayerWindow_) and such into the destructor of the class, videoPlayerWindow is an instance of.
Checks against NULL aren't a problem - and smart pointers don't meddle with that anyway.
Related
I'm a c++ newbie, my code currently new's up on the heap in several places without calling delete. I know I need to do something about this.
My typical usage is where I new up a class instance in another classes member method then the method returns the pointer to the object.
If i change the return types from MyType* to std::tr1::shared_ptr will this fix my code to not leak memory?
Thanks a lot.
Edit:
Also likewise, I currently store new'ed up objects as MyType* as a value in a std:map. This map is a private member to a class instance. If I simply change this to std::tr1::shared_ptr will this clear up these when it's owner (class) falls out of scope?
Thanks again
It's a reasonable band-aid, sure.
A shared pointer is a reference-counted pointer. So as long as one or more shared_ptrs exist pointing to an object, that object will be kept alive. The problem occurs if you have circular references. Then the reference count will never reach 0, and the object(s) will never be deleted.
So shared_ptr * still* require you to understand what you're doing and think about object ownership, as you always have to do in C++. But it simplifies some otherwise complex scenarios, where determining ownership is hard.
But the real fix to your problem is to:
minimize how much you allocate with new. Can the object instead be stored on the stack? Can the object be rewritten as a RAII class, so that a small wrapper object is allocated on the stack (or elsewhere with automatic storage duration), and which, through its constructors and destructors, manages a heap-allocated memory resource? Then, as long as that object exists, its allocated memory will be preserved, and once it is destroyed, it will delete its allocated memory.
when you allocate objects with new, put them in one of the smart pointer classes. shared_ptr is popular because it is the one that comes closest to looking like a garbage collector, but it isn't, and if you treat it as one and use it as an excuse to not think about memory management, then it won't work. Understand all the smart pointer classes (scoped_ptr and auto_ptr in C++03, or unique_ptr replacing both in C++11, shared_ptr and weak_ptr), and use the one that best fits your scenario.
think about ownership. Any time you allocate memory, you need to determine an owner, whose lifetime will control the lifetime of the memory allocation. Think about how long a lifetime your allocation needs, and have another object (whose lifetime is automatically managed, probably because it is on the stack) delete your memory when its destructor is called.
There's no quick and easy fix. The way to handle memory management in C++ is to avoid memory management. Delegate it out to your objects. If you're calling delete in your own code, you're doing it wrong. Often, you don't even need new, but if you do, assign ownership to a smart pointer immediately, and let that call delete for you.
As a rule of thumb, unless you're a library writer, you shouldn't write either new or delete. You should virtually never use raw pointers, and only when it is absolutely necessary, use smart pointers. Let your classes do the heavy lifting. Don't be afraid to put them on the stack, pass them by value, and let them handle their resources internally.
If you are new to C++ there are a few points with pointer management you need to understand and accept, regardless of whether you're using shared_ptr or not.
It is more than likely in your use of C++ you will need to use new and assign its return pointer to a class pointer that you have declared. I believe it is advisable to take the time to understand what is going on there, even if you write a small test program and watch the constructor execute in the debugger.
If you use classes like std::string, its constructors and destructor will do string pointer management for you, but I believe it is a good idea to understand what is going on behind the scenes in that class, if nothing more than reading the documentation.
As another example, you cannot use some classes, without a lot of detailed reading of the API, or you'll get problems. I once worked at company that used a commercial class package years ago. Someone had written a multi-threaded program using this package's thread pool class.
The documentation clearly said you can't just exit with outstanding threads. Yet I saw where the author of the program did not bother to synch up and shutdown all threads on exit, and wound up throwing exceptions, when their program exited. And this was on a commercial financial product.
My suggestion is don't look to get saved from performing pointer management. There are std classes like string that can reduce your headaches, but nothing will prevent problems other than your own diligence and testing.
As long as you understand how tr1 shared pointers work, yes.
Look at Boost C++ shared_ptr<> also - it might be more what you want.
I have a set of objects in a vector of pointers to their baseclass held inside a manager:
std::vector<object*> objectVec;
Classes may wish to spawn one of these objects using the Add() method in the manager. The problem is that they then subsequently need to set or update these objects themselves. I've decided to have Add() return a pointer to the object itself, which is stored in whatever class has decided to spawn one. The problem is dealing with the case where the object behind that pointer may have been deleted.
Add looks like this:
object* ObjectManager::Add(object* obj)
{
objectVec.push_back(obj);
return objectVec.back();
}
and used like this:
objectptr = ObjectManager::OMan()->Add(new object());
Where objectptr is a member of whatever class has called the function. So should that particular object be deleted, the pointer returned by Add would point to rubbish.
Is it my responsibility to ensure that whateverclass::objectptr is always set to NULL if this object is deleted? Or can this be dealt with using some sort of smart pointer? The problem being that I don't need to use a smart pointer to deal with the possibility of a memory leak, but to deal with the case where the stored pointer has become invalid.
Please let me know if i've been unclear, or if the question is badly formed.
Any help would be greatly appreciated.
Yes, you can store smart ptr's instead of raw ptr's in your vector. In this case if somebody releases an object, it's not deleted until the last reference is not released (the one held in vector in your case). You can use boost::shared_ptr or std::shared_ptr (C++11).
If this is not what you want, you can use boost::weak_ptr to store references in your vector. weak_ptr doesn't increment reference counter so if somebody releases an object, it's get deleted, but reference (weak_ptr) stored in your vector allows you to check this.
You likely want weak_ptr and shared_ptr. shared_ptr is a general smart pointer class. weak_ptr is an observer of shared_ptr. When all the references of the shared_ptr go away, instances of weak_ptr "become null" and are easier to deal with than a pointer to a deleted object.
These classes come with Boost.
http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr.htm
http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/weak_ptr.htm
And if I'm not mistaken, there are equivalents built into std namespace on compilers that implement newer C++0x standards. Visual C++ keeps has this built in.
http://blogs.msdn.com/b/vcblog/archive/2011/02/16/10128357.aspx
Oh shoot, looks like everyone else beat me to the answer...
Best is to forget this "manager" idea, but if you do or if you don't, the solution to shared ownership is the same as always, use boost::shared_ptr.
Or, with relatively new compiler, use std::shared_ptr.
Considering that with shared_ptr the ownership issue is taken care of already, then ask yourself, what is it that the "manager" manages?
Cheers & hth.,
Is it my responsibility to ensure that whateverclass::objectptr is always set to NULL if this object is deleted?
You're writing the class, so it's up to you to decide. This is a design decision and either choice is admissible, provided that you document it:
design the application
write the documentation/specification
write the code to matches the specification
Or can this be dealt with using some sort of smart pointer?
Using a smart pointer (strong or weak version) will help achieve whatever behavior you chose for the class. However, it will also strongly affect the client code. In the following code:
class Scene
{
// can't use this object in a call to `ObjectManager::Add()`,
// assuming it uses a smart pointer to deal with object lifetimes.
Object myLight;
};
The use cases for the ObjectManager class should be taken into consideration, on top of simplicity of implementation. Think "write once, use a lot".
Dangling pointers and memory leaks are two different issues, but a proper shared pointer can protect from both. For this particular case, I'd suggest boost::shared_ptr.
Use std::vector<boost::shared_ptr<BaseType>> for the vector type and also have the objects that hold the bare pointers now hold instead a boost::shared_ptr<BaseType>. This will ensure that the pointers will stay valid in the vector and in the objects as long as one of those objects still exist.
If you have differing requirements, you can use a boost::weak_ptr in one of the places holding the pointer (either the vector or the object).
Also, the object can hold a derived type instead of a base type (boost::shared_ptr<DerivedType>) and you can convert between them using boost::shared_static_cast.
Here is the documentation for all of these concepts.
I'm wondering if anyone's run across anything that exists which would fill this need.
Object A contains an object B. It wants to provide access to that B to clients through a pointer (maybe there's the option it could be 0, or maybe the clients need to be copiable and yet hold references...whatever). Clients, lets call them object C, would normally, if we're perfect developers, be written carefully so as to not violate the lifetime semantics of any pointer to B they might have...but we're not perfect, in fact we're pretty dumb half the time.
So what we want is for object C to have a pointer to object B that is not "shared" ownership but that is smart enough to recognize a situation in which the pointer is no longer valid, such as when object A is destroyed or it destroys object B. Accessing this pointer when it's no longer valid would cause an assertion/exception/whatever.
In other words, I wish to share access to data in a safe, clear way but retain the original ownership semantics. Currently, because I've not been able to find any shared pointer in which one of the objects owns it, I've been using shared_ptr in place of having such a thing. But I want clear owneship and shared/weak pointer doesn't really provide that.
Would be nice further if this smart pointer could be attached to member variables and not just hold pointers to dynamically allocated memory regions.
If it doesn't exist I'm going to make it, so I first want to know if someone's already released something out there that does it.
And, BTW, I do realize that things like references and pointers do provide this sort of thing...I'm looking for something smarter.
boost::weak_ptr is what you are looking for. Maybe with some minor tweaks though, like prohibiting creation of shared_ptr from it. Also, this can hold anything, including pointer to memory that is not dynamically allocated.
The semantics you want is similar to Qt's QPointer. This is a pointer that can hold QObjects and nulls itself when the corresponding QObject is deleteed (ordinarily, eg. by operator delete).
However, similar approach has inherent problems - such that the client cannot be sure he isn't using a dangling pointer. eg.
QPointer<T> smart_ptr = original_obj;
T* tmp = smart_ptr; // this might be a function argument etc.
... // later
delete original_obj;
... // even later
tmp->do_something(); // CRASH
This can be avoided using some "hard" references that don't allow object deletion, which is exactly what shared_ptr/weak_ptr do.
BTW, AFAIK, shared_ptr can point to member variables, except it can't manage them. That is, you must provide a custom deleter that doesn't do anything.
I have a class that contains a vector of object pointers. I have a GetObject(..) function in that class that looks through the vector, finds the object desired, and returns a pointer to it. However, if the user of the class does a delete() on that returned pointer, my program will crash because the vector still has a pointer to that, now invalid, object. So, in my GetObject() class, I can return a const pointer, but that doesn't solve the problem because you can still delete the object. The object is mutable so I can't return a pointer to a const object. I suppose I could prevent deletion by returning a reference to the object but I have my function returning NULL if there is an error. I guess I can pass back the object reference via the parameters and then return and error number like this
//-1 on object on found. 0 for success. Object is passed back in
// the function parameter result.
int MyObject::GetObject(int object_id, Item& result)
Is this the best solution for such a situation?
The best way to solve this problem is to use a shared-ownership smart pointer like shared_ptr, which you can find in Boost, C++ TR1, and C++0x.
A smart pointer is a container that manages the lifetime of your dynamically allocated object for you. It takes responsibility for deleteing the object when you are done using it.
With a shared ownership smart pointer, you can have multiple smart pointers that all share ownership of the dynamically allocated object. A reference count is kept that keeps track of how many smart pointers have ownership of the object, and when the last owning smart pointer is destroyed, the dynamically allocated object is deleted.
It is extremely difficult to manage resources manually in C++, and it's very easy to write code that looks correct and works right most of the time but that is still not correct. By using smart pointers and other resource-owning containers (like the standard library containers), you no longer have to manage resource manually. It is significantly easier to write correct code when all of your resource management is automatic.
Automatic resource management in C++ is accomplished using a design pattern called Resource Acquisition is Initialization (RAII), which is arguably the most important design pattern you as a C++ programmer should become familiar with.
Anybody in your code could also try to de-reference NULL. You going to stop them doing that too? If your container owns the object, and you make this clear (returning a raw pointer is usually pretty clear or mention in docs), then anyone who deletes it, the result is their own fault. The only way that you could guarantee the prevention of the deletion of the object is to prevent the user from ever gaining a native reference or pointer - in which case they just can't access the object.
Who are clients of your class? If they are not your mortal enemies you could just ask them nicely not to delete the object. Otherwise, there will always be a way for "them" to mess you up.
Okay, one possible solution is to make destructor private. That will prevent everyone from deleting the object. But then the object has to delete itself (delete this) somehow, maybe through some function called DeletObjectButDontBlameMeIfAppCrashes. If the owner is some other class then you can set the destructor to protected and owner class as friend of this class.
You should return a reference to the object. There are two ways to handle the case when there is no object found.
First, you can use the Null Object Pattern in order to implement a special value for that case. That might not make sense for your case though.
The other way is to split it up into two methods, one which can be used to check if an appropriate element exists, and one to retrieve it.
Many STL-containers or algorithms implement both of these, either by returned a past-the-end iterator, or by having empty() returns false as a prerequisite of calling a method like front or back.
If you can use the boost libraries, smart pointers can be used to ensure that pointers stay valid. Essentially, each reference to a smart pointer increases its "use count" by 1. When the reset function is called on a reference, the reference goes away and the use counter decrements. As long as some object is still holding on to a smart pointer, the reference will be valid. Note that the other classes will be able to change what its pointing to, but can't delete it.
(My description deals mainly with smart pointers specifically - the different types of pointers vary a little, but the general idea remains the same).
I have a piece of C++ classes and I have the raw pointer to the objects. The pointer to the object would get passed down to the function. The problem is the underlying function might need to store the pointer at times in an STL container in which pointer to the object would be used later on. If I am not using shared_ptr, I am thinking of adding a bool flag to the class which indicates whether the caller of the function is responsible for deleting the object memory. Would that be fine?
Thanks.
Messy. And rife with many potential bugs that will keep you at work well past midnight on a Saturday.
Be clear and consistent about resource ownership. Either the vector owns the pointers, or some specific function owns the pointers, or smart pointers own pointers. Any mixing of these semantics will have the ultimate result of you tearing your hair out late at night.
The best solution is usually to use a reference-counted smart pointer. (As you probably already know all to well, you can't use std::auto_ptr) Barring that, create a class whose sole purpose in life is to allocate, deallocate and grant access to the vector's contained pointers. Any function that needs the contained object would go through your manager class to get to them.
STL containers will almost certainly take a copy of the object which you insert into it. When the object is removed from the container, the object will be destroyed.
If the default copy constructor is not sufficient (i.e. you need to do a deep copy of the object), you need to ensure you implement your own version which does the copy properly.