I'm refreshing my C++ knowledge after not having used it in anger for a number of years. In writing some code to implement some data structure for practice, I wanted to make sure that my code was exception safe. So I've tried to use std::auto_ptrs in what I think is an appropriate way. Simplifying somewhat, this is what I have:
class Tree
{
public:
~Tree() { /* delete all Node*s in the tree */ }
void insert(const string& to_insert);
...
private:
struct Node {
...
vector<Node*> m_children;
};
Node* m_root;
};
template<T>
void push_back(vector<T*>& v, auto_ptr<T> x)
{
v.push_back(x.get());
x.release();
}
void Tree::insert(const string& to_insert)
{
Node* n = ...; // find where to insert the new node
...
push_back(n->m_children, auto_ptr<Node>(new Node(to_insert));
...
}
So I'm wrapping the function that would put the pointer into the container, vector::push_back, and relying on the by-value auto_ptr argument to
ensure that the Node* is deleted if the vector resize fails.
Is this an idiomatic use of auto_ptr to save a bit of boilerplate in my
Tree::insert? Any improvements you can suggest? Otherwise I'd have to have
something like:
Node* n = ...; // find where to insert the new node
auto_ptr<Node> new_node(new Node(to_insert));
n->m_children.push_back(new_node.get());
new_node.release();
which kind of clutters up what would have been a single line of code if I wasn't
worrying about exception safety and a memory leak.
(Actually I was wondering if I could post my whole code sample (about 300 lines) and ask people to critique it for idiomatic C++ usage in general, but I'm not sure whether that kind of question is appropriate on stackoverflow.)
It is not idiomatic to write your own container: it is rather exceptional, and for the most part useful only for learning how to write containers. At any rate, it is most certainly not idiomatic to use std::autp_ptr with standard containers. In fact, it's wrong, because copies of std::auto_ptr aren't equivalent: only one auto_ptr owns a pointee at any given time.
As for idiomatic use of std::auto_ptr, you should always name your auto_ptr on construction:
int wtv() { /* ... */ }
void trp(std::auto_ptr<int> p, int i) { /* ... */ }
void safe() {
std::auto_ptr<int> p(new int(12));
trp(p, wtv());
}
void danger() {
trp(std::auto_ptr<int>(new int(12)), wtv());
}
Because the C++ standard allows arguments to evaluate in any arbitrary order, the call to danger() is unsafe. In the call to trp() in danger(), the compiler may allocate the integer, then create the auto_ptr, and finally call wtv(). Or, the compiler may allocate a new integer, call wtv(), and finally create the auto_ptr. If wtv() throws an exception then danger() may or may not leak.
In the case of safe(), however, because the auto_ptr is constructed a-priori, RAII guarantees it will clean up properly whether or not wtv() throws an exception.
Yes it is.
For example, see the interface of the Boost.Pointer Container library. The various pointer containers all feature an insert function taking an auto_ptr which semantically guarantees that they take ownership (they also have the raw pointer version but hey :p).
There are however other ways to achieve what you're doing with regards to exception safety because it's only internal here. To understand it, you need to understand what could go wrong (ie throw) and then reorder your instructions so that the operations that may throw are done with before the side-effects occur.
For example, taking from your post:
auto_ptr<Node> new_node(new Node(to_insert)); // 1
n->m_children.push_back(new_node.get()); // 2
new_node.release(); // 3
Let's check each line,
The constructor may throw (for example if the CopyConstructor of the type throws), in this case however you are guaranteed that new will perform the cleanup for you
The call to push_back may throw a std::bad_alloc if the memory is exhausted. That's the only error possible as copying a pointer is a no-throw operation
This is guaranteed not to throw
If you look closely, you'll remark that you would not have to worry if you could somehow have 2 being executed before 1. It is in fact possible:
n->m_children.reserve(n->m_children.size() + 1);
n->m_children.push_back(new Node(to_insert));
The call to reserve may throw (bad_alloc), but if it completes normally you are then guaranteed that no reallocation will occur until size becomes equal to capacity and you try another insertion.
The call to new may fall if the constructor throw, in which case new will perform the cleanup, if it completes you're left with a pointer that is immediately inserted in the vector... which is guaranteed not to throw because of the line above.
Thus, the use of auto_ptr may be replaced here. It was nonetheless a good idea, though as has been noted you should refrain from executing RAII initialization within a function evaluation.
I like the idea of declaring the ownership of pointer. This is one of the great features in c++0x, std::unique_ptrs. However std::auto_ptr is so hard to understand and lethal is even slightly misued I would suggest avoiding it entirely.
http://www.gotw.ca/publications/using_auto_ptr_effectively.htm
Related
Conceptual Question
Say we have simple example like this:
void foo(std::unique_ptr<int> ptr)
{
std::cout << *ptr.get() << std::endl;
}
int main()
{
std::unique_ptr<int> uobj = std::make_unique<int>(4);
foo(uobj ); // line-(1) Problem ,but Alternative -> foo(std::move(uobj ))
std::unique_ptr<int> uobjAlt = uobj; // line-(2) Problem ,but Alternative -> std::unique_ptr<int> uobjAlt = std::move(uobj);
return EXIT_SUCCESS;
}
We know simply std::unique_ptr bound with concept of resource owning by single owner with moving resource among multiple owners while shared_ptr has opposite aspect.
As example shown above, when you look at line-(1) & line-(2) you notice that some standard rules are being violated because std::unique_ptr has(deleted) no both copy constructors and copy assignable operators defined, but In order to avoid compilation errors we have to use std::move function instead.
Problem
Why modern C++ compiler cannot automatically generate instructions to move the resource among unique pointers in line-(1) and line-(2)? because we know unique pointer intentionally design for that. Why should we use std::move explicitly to instruct the machine to move ownership of the resource?
std::unique_ptr nothing but class template.we know that, But situations addressed in line-1 and line -2 having issues while compiler complain about copying unique_pointers not allowed(deleted functions).why we having these kind of errors why c++ standard and compiler vendors cannot override this concept?
Unique Pointer intentionally designed for the purpose of moving resource while passing its ownership, when we pass it as function/constructor argument or assign to another unique pointer, it conceptually should move resource with ownership nothing else, but why we should use std::move to convey compiler to actual move, why don't we have a freedom to call line-(1) and line-(2) as it is? (while intelligent compiler generate automatic move operation among unique pointers for us, unless there is const or non-const reference passing).
(Sorry for long description and broken English) Thank you.
unique_ptr is useful to free memory for you automatically when uobj goes out of scope. That's its job. So, since it has 1 pointer it has to free, it has to be unique, and hence its name: unique_ptr!
When you do something like this:
std::unique_ptr<int> uobjAlt = uobj;
You're issuing a copy operation, but, you're not supposed to copy the pointer, because copying means that both objects uobjAlt and uobj must both be freed, which will directly lead to a segmentation fault and a crash. So, by using std::move, you're moving ownership from one object to another.
If you want to have multiple pointers to a single object, you should consider using std::shared_ptr.
This has nothing to do with whether the compiler can do this. It certainly could work that way, and in fact, it did work that way prior to C++11 with std::auto_ptr<>. It was horrible.
std::auto_ptr<int> x = std::auto_ptr<int>(new int(5));
std::auto_ptr<int> y = x;
// Now, x is NULL
The problem here is that the = sign usually means "copy from x to y", but in this case what is happening is "move from x to y, invalidating x in the process". Yes, if you are a savvy programmer you would understand what is going on here and it wouldn't surprise you, at least not all of the time. However, in more common situations it would be horribly surprising:
Here's MyClass.h:
class MyClass {
private:
std::auto_ptr<Type> my_field;
...
};
Here's MyClass.cpp:
void MyClass::Method() {
SomeFunction(my_field);
OtherFunction(my_field);
}
Here's Functions.h:
// Which overload, hmm?
void SomeFunction(Type &x);
void SomeFunction(std::auto_ptr<Type> x);
void OtherFunction(const std::auto_ptr<Type> &x);
Now you have to look at three different files before you can figure out that my_field is set to NULL. With std::unique_ptr you only have to look at one:
void MyClass::Method() {
SomeFunction(std::move(my_field));
OtherFunction(my_field);
}
Just looking at this one function I know that it's wrong, I don't have to figure out which overload is being used for SomeFunction, and I don't have to know what the type of my_field is. There's definitely a balance that we need to have between making things explicit and implicit. In this case, the fact that you couldn't explicitly tell the difference between moving and copying a value in C++ was such a problem that rvalue references, std::move, std::unique_ptr, etc. were added to C++ to clear things up, and they're pretty amazing.
The other reason why auto_ptr was so bad is because it interacted poorly with containers.
// This was a recipe for disaster
std::vector<std::auto_ptr<Type> > my_vector;
In general, many templates worked poorly with auto_ptr, not just containers.
If the compiler were allowed to auto-infer move semantics for types such as std::unique_ptr, code like this would break:
template<typename T> void simple_swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
The above counts on tmp being a copy of a (because it continues to use a as the left-hand side of as assignment operator). There is code in the standard algorithms which actually requires temporary copies of container values. Inferring moves would break them, causing crashes at run-time. This is why std::auto_ptr was warned against ever being used in STL containers.
Currently, I have a design that maps objects by a key, in an unordered_map. The problem is that in the constructor of this object, I need to look it up by the key- even though it doesn't exist yet. So far I have solved this problem by deferring everything, but it's quite awkward.
So I've been considering a kind of in-place-initializer. Something like
std::unordered_map<K, std::unique_ptr<T, FunkyDeleter>> map;
T* ptr = malloc(sizeof(T));
map[key] = std::unique_ptr<T, FunkyDeleter>(ptr);
try {
new (ptr) T(args);
} catch(...) {
map[key].release();
map.erase(key);
free(ptr);
throw;
}
This way, code in T's constructor can look it up in the map, even though it's not fully constructed yet.
What are the risks and problems inherent in this design? So far I identified exception safety, the destructor for the unique_ptr is gonna be awkward, as well as the risks of accessing a half-constructed T.
Edit:
Roughly speaking, T represents a node in a graph which is very definitely not acyclic and never will be acyclic, ever. In T's constructor, to calculate some things about T, I wanted to look at T's subnodes- which can contain direct references to that T instance. Imagine something like
struct K {
std::vector<K*> subkeys;
};
class T {
std::vector<T*> child_nodes;
public:
T(K* key, graph& graph) {
for(auto subkey : keys->subkeys)
child_nodes.push_back(graph.get(subkey));
}
std::vector<T*> children() { return child_nodes; }
};
class graph {
std::unordered_map<K*, std::unique_ptr<T>> nodes;
public:
T* get(K* key) {
if (nodes.find(key) == nodes.end())
nodes[key] = std::unique_ptr<T>(new T(key, *this));
return nodes[key].get();
}
};
int main() {
graph g;
K key1;
K key2;
key1.subkeys.push_back(&key2);
key2.subkeys.push_back(&key1);
g.get(&key1);
}
This obviously doesn't work in the case of cyclic references in K objects. The problem is how I'm going to support them. So far I simply deferred all work so that T simply does not evaluate any potentially referencing code in the constructor, but that leads to some very awkward designs in some places. I wanted to try and place the pointer to the T into the map as it's being constructed, so that circular references evaluate correctly in the constructor and I can throw out this deferred work, as some of it actually has important side-effects (which I cannot avoid due to a third-party design) and managing deferred side-effects is a bitch.
When you have such tight dependencies, in general constructor and destructor easily become a mess.
In general, you should avoid such things. Sometimes, it's just clearer to construct objects in an invalid state, and then initialize them with an initialize method. If you have some instance fields that you would like to be const, you can group them in a non-const struct field with const fields, that it assigned by initialize. You can even define some form of optional which can never be assigned more than once, but maybe that's overshooting.
Getting back to the question, what I see is:
The destructor of unique_ptr will call delete on a pointer which was not allocated with new, which is undefined behavior. You should use a unique_ptr with a dedicated/noop deallocator, unless you can control all the code which might remove that thing from the map, and be sure it uses that same release-erase-free boilerplate you used in your catch clause.
unique_ptr is meant to also work with incomplete types, so it will not try to access your object, and your T* is segregated inside the function. So you can only access a partially constructed T if:
T's constructor itself leaks a reference (this would be independent from your code here), or
Someone other thread tries to lookup for the new item. Doesn't seem to be the case, if your map is also local to the function. If you're doing multithread, then you must change your design, unless performance are not important. Because the only thing to do here is a reentrant mutex lock on the map, which would destroy all benefits you could get from multithreading.
EDIT
In response to your edit. First of all, it seems clean to me. Doesn't look like you're doing something weird. But you have to deal with the destructor problem, because your map will eventually get destroyed (program termination also causes destructors to be called).
Anyway:
I think you're using keys in a weird way. If the key itself already contains information about the subnodes, why are you also duplicating that information in the node itself? Information duplication calls for out-of-sync-data bugs.
Can't you just change T constructor to check the subkey before the lookup, and avoid looking for its own key?
I was recently introduced to the existence of auto_ptr and shared_ptr and I have a pretty simple/naive question.
I try to implement a data structure and I need to point to the children of a Node which (are more than 1 and its) number may change. Which is the best alternative and why:
class Node
{
public:
// ...
Node *children;
private:
//...
}
class Node
{
public:
// ...
share_ptr<Node> children;
private:
//...
}
I am not sure, but I think auto_ptr does not work for arrays. I am not, also, sure about whether I should use double pointers. Thanks for any help.
You're right that auto_ptr doesn't work for arrays. When it destroys the object it owns, it uses delete object;, so if you used new objects[whatever];, you'll get undefined behavior. Perhaps a bit more subtly, auto_ptr doesn't fit the requirements of "Copyable" (as the standard defines the term) so you can't create a container (vector, deque, list, etc.) of auto_ptr either.
A shared_ptr is for a single object as well. It's for a situation where you have shared ownership and need to delete the object only when all the owners go out of scope. Unless there's something going on that you haven't told us about, chances are pretty good that it doesn't fit your requirements very well either.
You might want to look at yet another class that may be new to you: Boost ptr_vector. At least based on what you've said, it seems to fit your requirements better than either auto_ptr or shared_ptr would.
I have used std::vector<std::shared_ptr<Node> > children successfully in a similar situation.
The main benefit of using a vector of shared_ptrs rather than an array is that all of the resource management is handled for you. This is especially handy in two situations:
1) When the vector is no longer in scope, it automatically calls delete on all of its contents. In this case, the reference count of the child Node will drop by 1 and if nothing else is referencing it, delete will be called on the object.
2) If you are referencing the Node elsewhere, there is no risk of being left with a dangling pointer to a deleted object. The object will only be deleted when there are no more references to it.
Unless you want behaviour that is substantially more complicated (perhaps there is a reason why an array is necessary), I would suggest this might be a good approach for you.
A simple implementation of the idea:
class Node {
private:
T contents;
std::vector<std::shared_ptr<Node> > children;
public:
Node(T value) : contents(value) {};
void add_child(T value) {
auto p = std::make_shared<Node>(value);
children.push_back(p);
}
std::shared_ptr<Node> get_child(size_t index) {
// Returning a shared pointer ensures the node isn't deleted
// while it is still in use.
return children.at(index);
}
void remove_child(size_t index) {
// The whole branch will be destroyed automatically.
// If part of the tree is still needed (eg. for undo), the
// shared pointer will ensure it is not destroyed.
children.erase(children.begin() + index);
}
};
auto_ptr is deprecated in favor of std::unique_ptr and btw. std::unique_ptr does work for arrays. You just need c++11 support. And there is already lots of resources about smart pointers and move semantics out there. The main difference between auto_ptr and unique_ptr is that auto_ptr does a move when you call the copy constructor and unique_ptr forbids the copy constructor, but allows a move when calling the move constructor. Therefore you need c++11 support with move semantics.
Stroustrup discusses the question of "What is an auto_ptr and why isn't there an auto_array" and concludes that there no need for the latter since the desired functionality can be accomplished with a vector.
http://www.stroustrup.com/bs_faq2.html#auto_ptr
I'm trying to learn C++, and trying to understand returning objects. I seem to see 2 ways of doing this, and need to understand what is the best practice.
Option 1:
QList<Weight *> ret;
Weight *weight = new Weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return &ret;
Option 2:
QList<Weight *> *ret = new QList();
Weight *weight = new Weight(cname, "Weight");
ret->append(weight);
ret->append(c);
return ret;
(of course, I may not understand this yet either).
Which way is considered best-practice, and should be followed?
Option 1 is defective. When you declare an object
QList<Weight *> ret;
it only lives in the local scope. It is destroyed when the function exits. However, you can make this work with
return ret; // no "&"
Now, although ret is destroyed, a copy is made first and passed back to the caller.
This is the generally preferred methodology. In fact, the copy-and-destroy operation (which accomplishes nothing, really) is usually elided, or optimized out and you get a fast, elegant program.
Option 2 works, but then you have a pointer to the heap. One way of looking at C++ is that the purpose of the language is to avoid manual memory management such as that. Sometimes you do want to manage objects on the heap, but option 1 still allows that:
QList<Weight *> *myList = new QList<Weight *>( getWeights() );
where getWeights is your example function. (In this case, you may have to define a copy constructor QList::QList( QList const & ), but like the previous example, it will probably not get called.)
Likewise, you probably should avoid having a list of pointers. The list should store the objects directly. Try using std::list… practice with the language features is more important than practice implementing data structures.
Use the option #1 with a slight change; instead of returning a reference to the locally created object, return its copy.
i.e. return ret;
Most C++ compilers perform Return value optimization (RVO) to optimize away the temporary object created to hold a function's return value.
In general, you should never return a reference or a pointer. Instead, return a copy of the object or return a smart pointer class which owns the object. In general, use static storage allocation unless the size varies at runtime or the lifetime of the object requires that it be allocated using dynamic storage allocation.
As has been pointed out, your example of returning by reference returns a reference to an object that no longer exists (since it has gone out of scope) and hence are invoking undefined behavior. This is the reason you should never return a reference. You should never return a raw pointer, because ownership is unclear.
It should also be noted that returning by value is incredibly cheap due to return-value optimization (RVO), and will soon be even cheaper due to the introduction of rvalue references.
passing & returning references invites responsibilty.! u need to take care that when you modify some values there are no side effects. same in the case of pointers. I reccomend you to retun objects. (BUT IT VERY-MUCH DEPENDS ON WHAT EXACTLY YOU WANT TO DO)
In ur Option 1, you return the address and Thats VERY bad as this could lead to undefined behaviour. (ret will be deallocated, but y'll access ret's address in the called function)
so use return ret;
It's generally bad practice to allocate memory that has to be freed elsewhere. That's one of the reasons we have C++ rather than just C. (But savvy programmers were writing object-oriented code in C long before the Age of Stroustrup.) Well-constructed objects have quick copy and assignment operators (sometimes using reference-counting), and they automatically free up the memory that they "own" when they are freed and their DTOR automatically is called. So you can toss them around cheerfully, rather than using pointers to them.
Therefore, depending on what you want to do, the best practice is very likely "none of the above." Whenever you are tempted to use "new" anywhere other than in a CTOR, think about it. Probably you don't want to use "new" at all. If you do, the resulting pointer should probably be wrapped in some kind of smart pointer. You can go for weeks and months without ever calling "new", because the "new" and "delete" are taken care of in standard classes or class templates like std::list and std::vector.
One exception is when you are using an old fashion library like OpenCV that sometimes requires that you create a new object, and hand off a pointer to it to the system, which takes ownership.
If QList and Weight are properly written to clean up after themselves in their DTORS, what you want is,
QList<Weight> ret();
Weight weight(cname, "Weight");
ret.append(weight);
ret.append(c);
return ret;
As already mentioned, it's better to avoid allocating memory which must be deallocated elsewhere. This is what I prefer doing (...these days):
void someFunc(QList<Weight *>& list){
// ... other code
Weight *weight = new Weight(cname, "Weight");
list.append(weight);
list.append(c);
}
// ... later ...
QList<Weight *> list;
someFunc(list)
Even better -- avoid new completely and using std::vector:
void someFunc(std::vector<Weight>& list){
// ... other code
Weight weight(cname, "Weight");
list.push_back(weight);
list.push_back(c);
}
// ... later ...
std::vector<Weight> list;
someFunc(list);
You can always use a bool or enum if you want to return a status flag.
Based on experience, do not use plain pointers because you can easily forget to add proper destruction mechanisms.
If you want to avoid copying, you can go for implementing the Weight class with copy constructor and copy operator disabled:
class Weight {
protected:
std::string name;
std::string desc;
public:
Weight (std::string n, std::string d)
: name(n), desc(d) {
std::cout << "W c-tor\n";
}
~Weight (void) {
std::cout << "W d-tor\n";
}
// disable them to prevent copying
// and generate error when compiling
Weight(const Weight&);
void operator=(const Weight&);
};
Then, for the class implementing the container, use shared_ptr or unique_ptr to implement the data member:
template <typename T>
class QList {
protected:
std::vector<std::shared_ptr<T>> v;
public:
QList (void) {
std::cout << "Q c-tor\n";
}
~QList (void) {
std::cout << "Q d-tor\n";
}
// disable them to prevent copying
QList(const QList&);
void operator=(const QList&);
void append(T& t) {
v.push_back(std::shared_ptr<T>(&t));
}
};
Your function for adding an element would make use or Return Value Optimization and would not call the copy constructor (which is not defined):
QList<Weight> create (void) {
QList<Weight> ret;
Weight& weight = *(new Weight("cname", "Weight"));
ret.append(weight);
return ret;
}
On adding an element, the let the container take the ownership of the object, so do not deallocate it:
QList<Weight> ql = create();
ql.append(*(new Weight("aname", "Height")));
// this generates segmentation fault because
// the object would be deallocated twice
Weight w("aname", "Height");
ql.append(w);
Or, better, force the user to pass your QList implementation only smart pointers:
void append(std::shared_ptr<T> t) {
v.push_back(t);
}
And outside class QList you'll use it like:
Weight * pw = new Weight("aname", "Height");
ql.append(std::shared_ptr<Weight>(pw));
Using shared_ptr you could also 'take' objects from collection, make copies, remove from collection but use locally - behind the scenes it would be only the same only object.
All of these are valid answers, avoid Pointers, use copy constructors, etc. Unless you need to create a program that needs good performance, in my experience most of the performance related problems are with the copy constructors, and the overhead caused by them. (And smart pointers are not any better on this field, I'd to remove all my boost code and do the manual delete because it was taking too much milliseconds to do its job).
If you're creating a "simple" program (although "simple" means you should go with java or C#) then use copy constructors, avoid pointers and use smart pointers to deallocate the used memory, if you're creating a complex programs or you need a good performance, use pointers all over the place, and avoid copy constructors (if possible), just create your set of rules to delete pointers and use valgrind to detect memory leaks,
Maybe I will get some negative points, but I think you'll need to get the full picture to take your design choices.
I think that saying "if you're returning pointers your design is wrong" is little misleading. The output parameters tends to be confusing because it's not a natural choice for "returning" results.
I know this question is old, but I don't see any other argument pointing out the performance overhead of that design choices.
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.