Replacing raw pointers in vectors with std::shared_ptr - c++

I have the following structure:
typedef Memory_managed_data_structure T_MYDATA;
std::vector<T_MYDATA *> object_container;
std::vector<T_MYDATA *> multiple_selection;
T_MYDATA * simple_selection;
Edit: this may be very important: the Memory_managed_data_structure contains, among other things, a bitter, raw pointer to some other data.
It aims to be a very simple representation of an original container of memory managed objects (object_container) and then a "multiple_selection" array (for selecting many objects in the range and doing various operations with them) and a "simple_selection" pointer (for doing these operations on a single object).
The lifetime of all objects is managed by the object_container while multiple_selection and simple_selection just point to some of them. multiple_selection and simple_selection can be nullified as needed and only object_container objects can be deleted.
The system works just fine but I am trying to get into shared_ptrs right now and would like to change the structure to something like:
typedef Memory_managed_data_structure T_MYDATA;
std::vector<std::shared_ptr<T_MYDATA> > object_container;
std::vector<std::shared_ptr<T_MYDATA> > multiple_selection;
std::shared_ptr<T_MYDATA> simple_selection;
Again, the object container would be the "owner" and the rest would just point to them. My question is, would this scheme wreak havok in the application?. Is there something I should know before snowballing into these changes?. Are not shared_ptr the appropriate kind of pointer here?.
I can somewhat guarantee that no object would exists in multiple_selection or simple_selection if it is not in object_container first. Of course, no delete is ever called in multiple_selection or simple_selection.
Thanks for your time.
Edit: Forgot to mention, never used any of these automated pointers before so I may be wildly confused about their uses. Any tips and rules of thumb will be greatly appreciated.

You say, that the object container would be the "owner" of the objects in question. In that case, that you have a clear owning relationship, using std::shared_ptr is not ideal. Rather, stick with what you have.
However, if you cannot guarantee, that a pointer has been removed from multiple_selection and/or simple_selection before it is deleted, you have to act. One possible action could be, that you use shared_ptr. In that case, an object could still continue to exist in one of the selections, even, if it is removed (via shared_ptr::reset or just assigning a null value) from object_container.
The other alternative is to make sure, that objects get removed thoroughly: If something is to be deleted, remove ALL references to it from the selections and from the object_container, and THEN delete it. If you strictly follow this scheme, you don't need the overhead of shared_ptr.

I can somewhat guarantee that no object would exists in
multiple_selection or simple_selection if it is not in
object_container first.
If you 150% sure, than there is no need for smart ptr.
Reason you may need it in this situation is debug, I think.
In case you describe - multiple_selection and simple_selection is not shared_ptr, but weak_ptr.
Code with error:
std::vector<int*> owner_vector;
std::vector<int*> weak_vector;
int* a = new int(3);
owner_vector.push_back(a);
weak_vector.push_back(a);
std::for_each(
owner_vector.begin(),
owner_vector.end(),
[](int* ptr) {
delete ptr;
}
);
std::for_each(
weak_vector.begin(),
weak_vector.end(),
[](int* ptr) {
*ptr = 3; // oops... usage of deleted pointer
}
);
You can catch it with smart pointers:
std::vector<std::shared_ptr<int>> owner_vector;
std::vector<std::weak_ptr<int>> weak_vector;
{
auto a = std::make_shared<int>();
owner_vector.push_back(a);
weak_vector.push_back(a);
}
std::for_each(
owner_vector.begin(),
owner_vector.end(),
[](std::shared_ptr<int>& ptr) {
ptr.reset(); // memory delete
}
);
std::for_each(
weak_vector.begin(),
weak_vector.end(),
[](std::weak_ptr<int>& ptr) {
assert(!ptr.expired()); // guarantee to be alive
auto shared_ptr = ptr.lock();
*shared_ptr = 3;
}
);
In last example you will have assert failed, but not undefined/segmentation fault. In not debug case you can disable shared_ptr overhead.

Related

If a function returns a std::unique_ptr, is it reasonable to assume each returned value is to a new object?

I'm learning about std::unique_ptr, trying to grok what it represents.
Given a function (out of my control) that returns a unique_ptr, is it implied/well understood that each invocation returns a unique_ptr that points to a new object (different than any prior invocation)?
By way of example, the following code produces a double-free on exit, and I hope that I correctly understand why: unique_ptrs delete their underlying object on destruction; therefore two unique_ptrs encapsulating the same memory/object would cause a double-free on destruction of the second. Therefore, would the following implementation of function getUniquePtr() be commonly/implicitly understood to be unreasonable?
// main.cpp
#include <memory>
#include <iostream>
std::unique_ptr<int> getUniquePtr() {
static int* p = new int(42);
return std::unique_ptr<int>(p);
}
class PtrOwner {
public:
std::unique_ptr<int> p_;
};
int main( int argc, char* argv[] ) {
PtrOwner po1;
PtrOwner po2;
po1.p_ = getUniquePtr();
po2.p_ = getUniquePtr();
return 0;
}
It should be assumed that, if a function returns std::unique_ptr<T>, then the returned smart pointer points to an object that is not currently managed by anyone else. This does not necessarily mean that it always refers to a different object. So long as this convention is followed, double-free bugs will be avoided. If this convention is violated, double-free bugs will occur.
For example, if you see some function like this:
std::unique_ptr<T> foo(std::unique_ptr<T> arg);
This function might, potentially, return std::move(arg) under some circumstances or it might destroy arg and return some other pointer. (You have to read the documentation to know what it does). This implies that you could do something like this:
auto t = std::make_unique<T>();
t = foo(std::move(t));
t = foo(std::move(t));
In this case, foo might just return the same pointer value twice, and this is perfectly safe. This example seems silly, but hopefully it gets my point across.
Yes, your assumptions are (mostly) correct. A unique_ptr owns the object exclusively, which implies that no two unique_ptrs should point to the same object at any given time.
As others have pointed out, this does not guarantee that multiple invocations of the same function returns different objects. This is because you can pass ownership around (by moving it), so if you pass ownership back to a function, as in Brians answer, it may well return the same object again, without braking any rules.
If you decide to manage an object by using smart pointers, try to avoid new and delete altogether. To create an object T that is owned by a unique_ptr, use make_unique<T>. This avoids the error of creating multiple unique_ptr to the same object. A unique_ptr is not copyable for exactly this reason. In other words, your getUniquePtr should be implemented like this:
return std::make_unique<int>(42);
One of the few reasons to construct a smart pointer from a raw pointer (as opposed to using make_unique) is when you have existing code or a library that works with raw pointers, which you cannot change.

Storing object references in a simple container

I am looking for a way to insert multiple objects of type A inside a container object, without making copies of each A object during insertion. One way would be to pass the A objects by reference to the container, but, unfortunately, as far as I've read, the STL containers only accept passing objects by value for insertions (for many good reasons). Normally, this would not be a problem, but in my case, I DO NOT want the copy constructor to be called and the original object to get destroyed, because A is a wrapper for a C library, with some C-style pointers to structs inside, which will get deleted along with the original object...
I only require a container that can return one of it's objects, given a particular index, and store a certain number of items which is determined at runtime, so I thought that maybe I could write my own container class, but I have no idea how to do this properly.
Another approach would be to store pointers to A inside the container, but since I don't have a lot of knowledge on this subject, what would be a proper way to insert pointers to objects in an STL container? For example this:
std::vector<A *> myVector;
for (unsigned int i = 0; i < n; ++i)
{
A *myObj = new myObj();
myVector.pushBack(myObj);
}
might work, but I'm not sure how to handle it properly and how to dispose of it in a clean way. Should I rely solely on the destructor of the class which contains myVector as a member to dispose of it? What happens if this destructor throws an exception while deleting one of the contained objects?
Also, some people suggest using stuff like shared_ptr or auto_ptr or unique_ptr, but I am getting confused with so many options. Which one would be the best choice for my scenario?
You can use boost or std reference_wrapper.
#include <boost/ref.hpp>
#include <vector>
struct A {};
int main()
{
A a, b, c, d;
std::vector< boost::reference_wrapper<A> > v;
v.push_back(boost::ref(a)); v.push_back(boost::ref(b));
v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
return 0;
}
You need to be aware of object lifetimes when using
reference_wrapper to not get dangling references.
int main()
{
std::vector< boost::reference_wrapper<A> > v;
{
A a, b, c, d;
v.push_back(boost::ref(a)); v.push_back(boost::ref(b));
v.push_back(boost::ref(c)); v.push_back(boost::ref(d));
// a, b, c, d get destroyed by the end of the scope
}
// now you have a vector full of dangling references, which is a very bad situation
return 0;
}
If you need to handle such situations you need a smart pointer.
Smart pointers are also an option but it is crucial to know which one to use. If your data is actually shared, use shared_ptr if the container owns the data use unique_ptr.
Anyway, I don't see what the wrapper part of A would change. If it contains pointers internally and obeys the rule of three, nothing can go wrong. The destructor will take care of cleaning up. This is the typical way to handle resources in C++: acquire them when your object is initialized, delete them when the lifetime of your object ends.
If you purely want to avoid the overhead of construction and deletion, you might want to use vector::emplace_back.
In C++11, you can construct container elements in place using emplace functions, avoiding the costs and hassle of managing a container of pointers to allocated objects:
std::vector<A> myVector;
for (unsigned int i = 0; i < n; ++i)
{
myVector.emplace_back();
}
If the objects' constructor takes arguments, then pass them to the emplace function, which will forward them.
However, objects can only be stored in a vector if they are either copyable or movable, since they have to be moved when the vector's storage is reallocated. You might consider making your objects movable, transferring ownership of the managed resources, or using a container like deque or list that doesn't move objects as it grows.
UPDATE: Since this won't work on your compiler, the best option is probably std::unique_ptr - that has no overhead compared to a normal pointer, will automatically delete the objects when erased from the vector, and allows you to move ownership out of the vector if you want.
If that's not available, then std::shared_ptr (or std::tr1::shared_ptr or boost::shared_ptr, if that's not available) will also give you automatic deletion, for a (probably small) cost in efficiency.
Whatever you do, don't try to store std::auto_ptr in a standard container. It's destructive copying behaviour makes it easy to accidentally delete the objects when you don't expect it.
If none of these are available, then use a pointer as in your example, and make sure you remember to delete the objects once you've finished with them.

C++ pointer container with reference counting

I need a collection in which i can store heap-allocated objects having virtual functions.
I known about boost::shared_ptr, std::unique_ptr (C++11) and boost::ptr_(vector|list|map), but they doesn't solve duplicate pointer problem.
Just to describe a problem - i have a function which accepts heap-allocated pointer and stores it for future use:
void SomeClass::add(T* ptr)
{
_list.push_back(ptr);
}
But if i call add twice with same parameter ptr - _list will contain two pointers to same object and when _list is destructed multiple deletion of same object will occur.
If _list will count pointer which he stores and uses them at deletion time then this problem will be solved and objects will not be deleted multiple times.
So the question is:
Does somebody knows some library with collections (vector,list,map in essence) of pointer with auto-delete on destruction and support of reference counting?
Or maybe i can solve this problem using some other technique?
Update:
I need support of duplicate pointers. So i can't use std::set.
As Kerrek SB and Grizzly mentioned - it is a bad idea to use raw pointers in general and suggests to use std::make_shared and forget about instantiation via new. But this is responsibility of client-side code - not the class which i designs. Even if i change add signature (and _list container of course) to
void SomeClass::add(std::shared_ptr<T> ptr)
{
_list.push_back(ptr);
}
then somebody (who doesn't know about std::make_shared) still can write this:
SomeClass instance;
T* ptr = new T();
instance.add(ptr);
instance.add(ptr);
So this is not a full solution which i wait, but useful if you write code alone.
Update 2:
As an alternative solution i found a clonning (using generated copy constructor). I mean that i can change my add function like this:
template <typename R>
void SomeClass::add(const R& ref)
{
_list.push_back(new R(ref));
}
this will allow virtual method (R - class which extends some base class (interface)) calls and disallow duplicate pointers. But this solution has an overhead for clone.
Yes: std::list<std::shared_ptr<T>>.
The shared pointer is avaiable from <memory>, or on older platforms from <tr1/memory>, or from Boost's <boost/shared_ptr.hpp>. You won't need to delete anything manually, as the shared pointer takes care of this itself. You will however need to keep all your heap pointers inside a shared pointer right from the start:
std::shared_ptr<T> p(new T); // legacy
auto p = std::make_shared<T>(); // better
If you another shared pointer to the same object, make a copy of the shared pointer (rather than construct a new shared pointer from the underlying raw pointer): auto q = p;
The moral here is: If you're using naked pointers, something is wrong.
Realize that smart pointers are compared by comparing the underlying container. So you can just use a std::set of whatever smartpointer you prefer. Personally I use std::unique_ptr over shared_ptr, whenever I can get away with it, since it makes the ownership much clearer (whoever holds the unique_ptris the owner) and has much lower overhead too. I have found that this is enough for almost all my code. The code would look something like the following:
std::set<std::unique_ptr<T> > _list;
void SomeClass::add(T* ptr)
{
std::unique_ptr<T> p(ptr);
auto iter = _list.find(p);
if(iter == _list.end())
_list.insert(std::move(p));
else
p.release();
}
I'm not sure right now if that is overkill (have to check if insert is guaranteed not to do anything, if the insertion fails), but it should work. Doing this with shared_ptr<T> would look similar, although be a bit more complex, due to the lack of a relase member. In that case I would probably first construct a shared_ptr<T> with a do nothing deleter too pass to the call to find and then another shared_ptr<T> which is actually inserted.
Of course personally I would avoid doing this and always pass around smart pointers when the ownership of a pointer changes hands. Therefore I would rewrite SomeClass::add as void SomeClass::add(std::unique_ptr<T> ptr) or void SomeClass::add(std::shared_ptr<T> ptr) which would pretty much solve the problem of having multiple instances anyways (as long as the pointer is always wrapped).

Example to use shared_ptr?

Hi I asked a question today about How to insert different types of objects in the same vector array and my code in that question was
gate* G[1000];
G[0] = new ANDgate() ;
G[1] = new ORgate;
//gate is a class inherited by ANDgate and ORgate classes
class gate
{
.....
......
virtual void Run()
{ //A virtual function
}
};
class ANDgate :public gate
{.....
.......
void Run()
{
//AND version of Run
}
};
class ORgate :public gate
{.....
.......
void Run()
{
//OR version of Run
}
};
//Running the simulator using overloading concept
for(...;...;..)
{
G[i]->Run() ; //will run perfectly the right Run for the right Gate type
}
and I wanted to use vectors so someone wrote that I should do that :
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
but then he and many others suggested that I would better use Boost pointer containers
or shared_ptr. I have spent the last 3 hours reading about this topic, but the documentation seems pretty advanced to me . ****Can anyone give me a small code example of shared_ptr usage and why they suggested using shared_ptr. Also are there other types like ptr_vector, ptr_list and ptr_deque** **
Edit1: I have read a code example too that included:
typedef boost::shared_ptr<Foo> FooPtr;
.......
int main()
{
std::vector<FooPtr> foo_vector;
........
FooPtr foo_ptr( new Foo( 2 ) );
foo_vector.push_back( foo_ptr );
...........
}
And I don't understand the syntax!
Using a vector of shared_ptr removes the possibility of leaking memory because you forgot to walk the vector and call delete on each element. Let's walk through a slightly modified version of the example line-by-line.
typedef boost::shared_ptr<gate> gate_ptr;
Create an alias for the shared pointer type. This avoids the ugliness in the C++ language that results from typing std::vector<boost::shared_ptr<gate> > and forgetting the space between the closing greater-than signs.
std::vector<gate_ptr> vec;
Creates an empty vector of boost::shared_ptr<gate> objects.
gate_ptr ptr(new ANDgate);
Allocate a new ANDgate instance and store it into a shared_ptr. The reason for doing this separately is to prevent a problem that can occur if an operation throws. This isn't possible in this example. The Boost shared_ptr "Best Practices" explain why it is a best practice to allocate into a free-standing object instead of a temporary.
vec.push_back(ptr);
This creates a new shared pointer in the vector and copies ptr into it. The reference counting in the guts of shared_ptr ensures that the allocated object inside of ptr is safely transferred into the vector.
What is not explained is that the destructor for shared_ptr<gate> ensures that the allocated memory is deleted. This is where the memory leak is avoided. The destructor for std::vector<T> ensures that the destructor for T is called for every element stored in the vector. However, the destructor for a pointer (e.g., gate*) does not delete the memory that you had allocated. That is what you are trying to avoid by using shared_ptr or ptr_vector.
I will add that one of the important things about shared_ptr's is to only ever construct them with the following syntax:
shared_ptr<Type>(new Type(...));
This way, the "real" pointer to Type is anonymous to your scope, and held only by the shared pointer. Thus it will be impossible for you to accidentally use this "real" pointer. In other words, never do this:
Type* t_ptr = new Type(...);
shared_ptr<Type> t_sptr ptrT(t_ptr);
//t_ptr is still hanging around! Don't use it!
Although this will work, you now have a Type* pointer (t_ptr) in your function which lives outside the shared pointer. It's dangerous to use t_ptr anywhere, because you never know when the shared pointer which holds it may destruct it, and you'll segfault.
Same goes for pointers returned to you by other classes. If a class you didn't write hands you a pointer, it's generally not safe to just put it in a shared_ptr. Not unless you're sure that the class is no longer using that object. Because if you do put it in a shared_ptr, and it falls out of scope, the object will get freed when the class may still need it.
Learning to use smart pointers is in my opinion one of the most important steps to become a competent C++ programmer. As you know whenever you new an object at some point you want to delete it.
One issue that arise is that with exceptions it can be very hard to make sure a object is always released just once in all possible execution paths.
This is the reason for RAII: http://en.wikipedia.org/wiki/RAII
Making a helper class with purpose of making sure that an object always deleted once in all execution paths.
Example of a class like this is: std::auto_ptr
But sometimes you like to share objects with other. It should only be deleted when none uses it anymore.
In order to help with that reference counting strategies have been developed but you still need to remember addref and release ref manually. In essence this is the same problem as new/delete.
That's why boost has developed boost::shared_ptr, it's reference counting smart pointer so you can share objects and not leak memory unintentionally.
With the addition of C++ tr1 this is now added to the c++ standard as well but its named std::tr1::shared_ptr<>.
I recommend using the standard shared pointer if possible. ptr_list, ptr_dequeue and so are IIRC specialized containers for pointer types. I ignore them for now.
So we can start from your example:
std::vector<gate*> G;
G.push_back(new ANDgate);
G.push_back(new ORgate);
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
The problem here is now that whenever G goes out scope we leak the 2 objects added to G. Let's rewrite it to use std::tr1::shared_ptr
// Remember to include <memory> for shared_ptr
// First do an alias for std::tr1::shared_ptr<gate> so we don't have to
// type that in every place. Call it gate_ptr. This is what typedef does.
typedef std::tr1::shared_ptr<gate> gate_ptr;
// gate_ptr is now our "smart" pointer. So let's make a vector out of it.
std::vector<gate_ptr> G;
// these smart_ptrs can't be implicitly created from gate* we have to be explicit about it
// gate_ptr (new ANDgate), it's a good thing:
G.push_back(gate_ptr (new ANDgate));
G.push_back(gate_ptr (new ORgate));
for(unsigned i=0;i<G.size();++i)
{
G[i]->Run();
}
When G goes out of scope the memory is automatically reclaimed.
As an exercise which I plagued newcomers in my team with is asking them to write their own smart pointer class. Then after you are done discard the class immedietly and never use it again. Hopefully you acquired crucial knowledge on how a smart pointer works under the hood. There's no magic really.
The boost documentation provides a pretty good start example:
shared_ptr example (it's actually about a vector of smart pointers) or
shared_ptr doc
The following answer by Johannes Schaub explains the boost smart pointers pretty well:
smart pointers explained
The idea behind(in as few words as possible) ptr_vector is that it handles the deallocation of memory behind the stored pointers for you: let's say you have a vector of pointers as in your example. When quitting the application or leaving the scope in which the vector is defined you'll have to clean up after yourself(you've dynamically allocated ANDgate and ORgate) but just clearing the vector won't do it because the vector is storing the pointers and not the actual objects(it won't destroy but what it contains).
// if you just do
G.clear() // will clear the vector but you'll be left with 2 memory leaks
...
// to properly clean the vector and the objects behind it
for (std::vector<gate*>::iterator it = G.begin(); it != G.end(); it++)
{
delete (*it);
}
boost::ptr_vector<> will handle the above for you - meaning it will deallocate the memory behind the pointers it stores.
Through Boost you can do it
>
std::vector<boost::any> vecobj;
boost::shared_ptr<string> sharedString1(new string("abcdxyz!"));
boost::shared_ptr<int> sharedint1(new int(10));
vecobj.push_back(sharedString1);
vecobj.push_back(sharedint1);
>
for inserting different object type in your vector container. while for accessing you have to use any_cast, which works like dynamic_cast, hopes it will work for your need.
#include <memory>
#include <iostream>
class SharedMemory {
public:
SharedMemory(int* x):_capture(x){}
int* get() { return (_capture.get()); }
protected:
std::shared_ptr<int> _capture;
};
int main(int , char**){
SharedMemory *_obj1= new SharedMemory(new int(10));
SharedMemory *_obj2 = new SharedMemory(*_obj1);
std::cout << " _obj1: " << *_obj1->get() << " _obj2: " << *_obj2->get()
<< std::endl;
delete _obj2;
std::cout << " _obj1: " << *_obj1->get() << std::endl;
delete _obj1;
std::cout << " done " << std::endl;
}
This is an example of shared_ptr in action. _obj2 was deleted but pointer is still valid.
output is,
./test
_obj1: 10 _obj2: 10
_obj2: 10
done
The best way to add different objects into same container is to use make_shared, vector, and range based loop and you will have a nice, clean and "readable" code!
typedef std::shared_ptr<gate> Ptr
vector<Ptr> myConatiner;
auto andGate = std::make_shared<ANDgate>();
myConatiner.push_back(andGate );
auto orGate= std::make_shared<ORgate>();
myConatiner.push_back(orGate);
for (auto& element : myConatiner)
element->run();

What are potential dangers when using boost::shared_ptr?

What are some ways you can shoot yourself in the foot when using boost::shared_ptr? In other words, what pitfalls do I have to avoid when I use boost::shared_ptr?
Cyclic references: a shared_ptr<> to something that has a shared_ptr<> to the original object. You can use weak_ptr<> to break this cycle, of course.
I add the following as an example of what I am talking about in the comments.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
if (parent_) parent_->frob();
}
private :
void do_frob();
shared_ptr<node> parent_;
vector< shared_ptr<node> > children_;
};
In this example, you have a tree of nodes, each of which holds a pointer to its parent. The frob() member function, for whatever reason, ripples upwards through the tree. (This is not entirely outlandish; some GUI frameworks work this way).
The problem is that, if you lose reference to the topmost node, then the topmost node still holds strong references to its children, and all its children also hold a strong reference to their parents. This means that there are circular references keeping all the instances from cleaning themselves up, while there is no way of actually reaching the tree from the code, this memory leaks.
class node : public enable_shared_from_this<node> {
public :
void set_parent(shared_ptr<node> parent) { parent_ = parent; }
void add_child(shared_ptr<node> child) {
children_.push_back(child);
child->set_parent(shared_from_this());
}
void frob() {
do_frob();
shared_ptr<node> parent = parent_.lock(); // Note: parent_.lock()
if (parent) parent->frob();
}
private :
void do_frob();
weak_ptr<node> parent_; // Note: now a weak_ptr<>
vector< shared_ptr<node> > children_;
};
Here, the parent node has been replaced by a weak pointer. It no longer has a say in the lifetime of the node to which it refers. Thus, if the topmost node goes out of scope as in the previous example, then while it holds strong references to its children, its children don't hold strong references to their parents. Thus there are no strong references to the object, and it cleans itself up. In turn, this causes the children to lose their one strong reference, which causes them to clean up, and so on. In short, this wont leak. And just by strategically replacing a shared_ptr<> with a weak_ptr<>.
Note: The above applies equally to std::shared_ptr<> and std::weak_ptr<> as it does to boost::shared_ptr<> and boost::weak_ptr<>.
Creating multiple unrelated shared_ptr's to the same object:
#include <stdio.h>
#include "boost/shared_ptr.hpp"
class foo
{
public:
foo() { printf( "foo()\n"); }
~foo() { printf( "~foo()\n"); }
};
typedef boost::shared_ptr<foo> pFoo_t;
void doSomething( pFoo_t p)
{
printf( "doing something...\n");
}
void doSomethingElse( pFoo_t p)
{
printf( "doing something else...\n");
}
int main() {
foo* pFoo = new foo;
doSomething( pFoo_t( pFoo));
doSomethingElse( pFoo_t( pFoo));
return 0;
}
Constructing an anonymous temporary shared pointer, for instance inside the arguments to a function call:
f(shared_ptr<Foo>(new Foo()), g());
This is because it is permissible for the new Foo() to be executed, then g() called, and g() to throw an exception, without the shared_ptr ever being set up, so the shared_ptr does not have a chance to clean up the Foo object.
Be careful making two pointers to the same object.
boost::shared_ptr<Base> b( new Derived() );
{
boost::shared_ptr<Derived> d( b.get() );
} // d goes out of scope here, deletes pointer
b->doSomething(); // crashes
instead use this
boost::shared_ptr<Base> b( new Derived() );
{
boost::shared_ptr<Derived> d =
boost::dynamic_pointer_cast<Derived,Base>( b );
} // d goes out of scope here, refcount--
b->doSomething(); // no crash
Also, any classes holding shared_ptrs should define copy constructors and assignment operators.
Don't try to use shared_from_this() in the constructor--it won't work. Instead create a static method to create the class and have it return a shared_ptr.
I've passed references to shared_ptrs without trouble. Just make sure it's copied before it's saved (i.e., no references as class members).
Here are two things to avoid:
Calling the get() function to get the raw pointer and use it after the pointed-to object goes out of scope.
Passing a reference of or a raw pointer to a shared_ptr should be dangerous too, since it won't increment the internal count which helps keep the object alive.
We debug several weeks strange behavior.
The reason was:
we passed 'this' to some thread workers instead of 'shared_from_this'.
Not precisely a footgun, but certainly a source of frustration until you wrap your head around how to do it the C++0x way: most of the predicates you know and love from <functional> don't play nicely with shared_ptr. Happily, std::tr1::mem_fn works with objects, pointers and shared_ptrs, replacing std::mem_fun, but if you want to use std::negate, std::not1, std::plus or any of those old friends with shared_ptr, be prepared to get cozy with std::tr1::bind and probably argument placeholders as well. In practice this is actually a lot more generic, since now you basically end up using bind for every function object adaptor, but it does take some getting used to if you're already familiar with the STL's convenience functions.
This DDJ article touches on the subject, with lots of example code. I also blogged about it a few years ago when I first had to figure out how to do it.
Using shared_ptr for really small objects (like char short) could be an overhead if you have a lot of small objects on heap but they are not really "shared". boost::shared_ptr allocates 16 bytes for every new reference count it creates on g++ 4.4.3 and VS2008 with Boost 1.42. std::tr1::shared_ptr allocates 20 bytes. Now if you have a million distinct shared_ptr<char> that means 20 million bytes of your memory are gone in holding just count=1. Not to mention the indirection costs and memory fragmentation. Try with the following on your favorite platform.
void * operator new (size_t size) {
std::cout << "size = " << size << std::endl;
void *ptr = malloc(size);
if(!ptr) throw std::bad_alloc();
return ptr;
}
void operator delete (void *p) {
free(p);
}
Giving out a shared_ptr< T > to this inside a class definition is also dangerous.
Use enabled_shared_from_this instead.
See the following post here
You need to be careful when you use shared_ptr in multithread code. It's then relatively easy to become into a case when couple of shared_ptrs, pointing to the same memory, is used by different threads.
The popular widespread use of shared_ptr will almost inevitably cause unwanted and unseen memory occupation.
Cyclic references are a well known cause and some of them can be indirect and difficult to spot especially in complex code that is worked on by more than one programmer; a programmer may decide than one object needs a reference to another as a quick fix and doesn't have time to examine all the code to see if he is closing a cycle. This hazard is hugely underestimated.
Less well understood is the problem of unreleased references. If an object is shared out to many shared_ptrs then it will not be destroyed until every one of them is zeroed or goes out of scope. It is very easy to overlook one of these references and end up with objects lurking unseen in memory that you thought you had finished with.
Although strictly speaking these are not memory leaks (it will all be released before the program exits) they are just as harmful and harder to detect.
These problems are the consequences of expedient false declarations: 1. Declaring what you really want to be single ownership as shared_ptr. scoped_ptr would be correct but then any other reference to that object will have to be a raw pointer, which could be left dangling. 2. Declaring what you really want to be a passive observing reference as shared_ptr. weak_ptr would be correct but then you have the hassle of converting it to share_ptr every time you want to use it.
I suspect that your project is a fine example of the kind of trouble that this practice can get you into.
If you have a memory intensive application you really need single ownership so that your design can explicitly control object lifetimes.
With single ownership opObject=NULL; will definitely delete the object and it will do it now.
With shared ownership spObject=NULL; ........who knows?......
If you have a registry of the shared objects (a list of all active instances, for example), the objects will never be freed. Solution: as in the case of circular dependency structures (see Kaz Dragon's answer), use weak_ptr as appropriate.
Smart pointers are not for everything, and raw pointers cannot be eliminated
Probably the worst danger is that since shared_ptr is a useful tool, people will start to put it every where. Since plain pointers can be misused, the same people will hunt raw pointers and try to replace them with strings, containers or smart pointers even when it makes no sense. Legitimate uses of raw pointers will become suspect. There will be a pointer police.
This is not only probably the worst danger, it may be the only serious danger. All the worst abuses of shared_ptr will be the direct consequence of the idea that smart pointers are superior to raw pointer (whatever that means), and that putting smart pointers everywhere will make C++ programming "safer".
Of course the mere fact that a smart pointer needs to be converted to a raw pointer to be used refutes this claim of the smart pointer cult, but the fact that the raw pointer access is "implicit" in operator*, operator-> (or explicit in get()), but not implicit in an implicit conversion, is enough to give the impression that this is not really a conversion, and that the raw pointer produced by this non-conversion is an harmless temporary.
C++ cannot be made a "safe language", and no useful subset of C++ is "safe"
Of course the pursuit of a safe subset ("safe" in the strict sense of "memory safe", as LISP, Haskell, Java...) of C++ is doomed to be endless and unsatisfying, as the safe subset of C++ is tiny and almost useless, as unsafe primitives are the rule rather than the exception. Strict memory safety in C++ would mean no pointers and only references with automatic storage class. But in a language where the programmer is trusted by definition, some people will insist on using some (in principle) idiot-proof "smart pointer", even where there is no other advantage over raw pointers that one specific way to screw the program state is avoided.