Related
Destructors of structs:
Could you specify every type of data type that would be have to be explicitly handled in the destructor of a struct?
struct Node {
int val; // representing any/all primitive data types
int* ptrToVal; // representing any/all pointers to primitive data types
int arr[5]; // representing any/all arrays
int* ptrToArr[5]; // representing any/all array of pointers
Node* next; // pointer to a struct
vector<Node> vOfNodes; // vector of structs
vector<Node*> vOfPtrs; // vector of struct pointers
unordered_map<int, Node*> um; //representing any pre-existing class template
// Default constructor
Node() : val(0), ptrToVal(nullptr), arr(), ptrToArr(), next(nullptr),
vOfNodes(), vOfPtrs(), um(){}
//Overloaded constructor
Node(int val, int* toVal, Node* n, vector<Node> vN, vector<Node*> toV,
unordered_map<int, Node*> m)
: val(val), ptrToVal(toVal), arr(), ptrToArr(), next(n),
vOfNodes(vN), vOfPtrs(toV), um(m){}
What would be necessary to add to the destructor of the Node struct? Is there any other tricky data structures that I didn’t couldn’t think of that would also necessitate non-trivial code in the destructor?
Anything could require explicit destruction: an int could be a file descriptor to be closed, an index into an array (external to the object) identifying an object to be finalized in some way, or a pointer stored as std::uintptr_t for type erasure reasons. A function pointer could be a registered cleanup function to be called. An object with its own destructor could contain information of any of these types that it doesn’t know how to handle.
On the other hand, a raw object pointer, which is the poster child for explicit destruction, might just be a non-owning (“observing”) pointer into another data structure and need no cleanup at all.
So there’s no predetermined answer: you have to consider why the object has each member and what it owns about each.
What would be necessary to add to the destructor of the Node struct?
Based on the code shown, nothing. Guessing a fair amount, maybe some delete statements. Ideally, nothing.
A destructor is mainly for "undoing" some earlier action associated with an object when that object's lifetime ends - like the corresponding delete to a new, or a file close to an open, or resetting temporary configuration changes back to originals, or etc. But nothing in those members just existing requires any C++ code to undo.
Though some of these members are or contain "ambiguous pointers". We can't tell just by looking how they're to be used: can pointers to any particular objects go there? Only pointers which came from new expressions? If they're from new expressions, is the struct "responsible" for cleaning up with an eventual delete (or delete[]), or does the code which did the new expressions still have responsibility for that? These questions could apply to every pointer involved: ptrToVal, next, and the elements within ptrToArr (misleadingly named), vOfPtrs, and/or um.
If the answer is that the struct is never responsible for doing delete, then the "raw pointer" is an okay choice after all, and the struct doesn't need a destructor declared. (C++ will automatically give it a destructor, and define it if needed.)
If the answer is that the struct should do some delete on some of those pointers, we could define its destructor to do that. But even better, we could change the members from raw pointers to smart pointers, like std::unique_ptr<Node> next; or std::vector<std::shared_ptr<Node>> vOfPtrs;. Smart pointers are one type of RAII handle (Resource Allocation Is Initialization) .
RAII handles in C++:
make it more obvious what the pattern is for cleanup responsibility
save us from nasty and hard to find bugs when new and delete, or other Do/Undo operations, are misused
save us from writing a lot of repetitive code in the first place
save us from explicitly dealing with extra tricky cases for exception safety, if things that should be automatically undone happen before or during a constructor
So if smart pointers are appropriately used, they take over the responsibility for undoing things, and a struct at the higher level doesn't need a destructor at all.
Then the one remaining reason to write a destructor which is more than just = default; or {} is then when implementing a brand new RAII handle, if it's not something just easily done by std::unique_ptr. And since an RAII handle should hold just one action to undo, that's usually a one-statement destructor.
I am implementing AVL tree in C++ and using unique_ptr for children.
struct Node
{
const int key;
std::unique_ptr<Node> left, right;
Node* parent;
std::size_t height; ///< for avl tree.
Node(const int key) : key(key), height(0) {}
};
class AVL
{
std::unique_ptr<Node> root;
public:
AVL(int rootKey) : root(std::unique_ptr<Node>(new Node(rootKey))) {
}
void insert(std::unique_ptr<Node> newNode) {
std::unique_ptr<Node> & node = root;
Node* parentWeak;
while(node.get()) {
parentWeak = node->parent;
if (node->key == newNode->key)
throw std::runtime_error("Key already present");
if (node->key < newNode->key)
node = node->right;
else
node = node->left;
}
auto parent = parentWeak;
const int key = newNode->key;
if (parent == nullptr) {
// there is no root
root = std::move(newNode);
} else {
if (parent->key < newNode->key) {
assert(NULL == parent->right.get());
parent->right = std::move(newNode);
} else {
assert(NULL == parent->left.get());
parent->left = std::move(newNode);
}
}
// Now increment the height upto down.
incrementHeight(key);
// balance starting from parent upwards untill we find some dislanace in height
balance(parent, key);
}
};
I am getting compiler errors on line node = node->right;. Which is right because it can be possible with only std::move semantics. but that would be wrong because i want to just iterate over the tree, otherwise it would just remove them from the child-list.
However, i need the unique_ptr also, as it would passed in function balance as it would modify the pointers and re-balance the tree.
If i use shared_ptr it would all work. However, i do not need to share the ownership with others. Or am i misunderstanding ownership ?
Your problem seems to be caused by a lack of understanding how to use unique_ptr in real programs, which is related to the concept of ownership. If a something owns an object, it means, this something is responsible for keeping the object alive as long as this something keeps owning the object, and is responsible to destroy the object as soon as nothing owns the object anymore.
Both unique_ptr and shared_ptr can be used to own objects. The difference, you seem to be aware of, is that an object pointed to by unique_ptr can only have a single owner, while there might be multiple shared_ptr objects sharing ownership of a specific object. If a unique_ptr is destroyed or assigned a different value, by definition it can destroy the object it previously pointed to, as a unique_ptr is the single (unique) owner of an object.
Now you have to think about your tree: You can use shared_ptr for everything, which will likely (seems to) work, as objects are kept alive as long as there are references to them. If there really is the parent member in node which you use in your method but did not declare in the node structuer, you would be likely to create reference cycles, though, creating the danger of keeping objects around way too long (or even forever, this is called a memory leak), as shared_ptr in C++ is purely reference-counted. Two objects containing shared_ptrs pointing to each other keep themselves alive forever, even if no other pointer points to them. It seems like in your shared_ptr solution, the parent member was a weak_ptr which is a sensible way to work around this problem, although possibly not the most efficient one.
You seem to want to improve performance and strictness of your code by using unique_ptr instead of shared_ptr which is commonly accepted as a very good idea, as it forces you to deal with ownership in much greater detail. Your choice that the tree owns the root node, and each node owns the children is a sound design. You seem to have removed the parent pointer, because it can not be a unique_ptr, as in that case, a node would be owned by its parents and any childrens it might have, violating the constraint that an object pointed to by unique_ptr may only have one owner. Also, the parent member can not be a weak_ptr, as weak_ptr can only be used with objects managed by shared_ptr. If you want to translate a design from shared_ptr to unique_ptr, you should consider changing weak_ptrs into raw pointers. A non-owning pointer to an object managed by unique_ptr that detects expiration of that object does not exist (it would not be effienctly implementable with the typical C++ memory management). If you need the property of being able to detect a non-owning pointer to be stale, keep using shared_ptr. The overhead for tracking non-owning pointers is almost as big as full shared-ownership semantics, so there is no middle ground in the standard library.
Finally, let's discuss the insert method. The node variable quite surely is not what you want. You correctly found out (possibly by a compiler error message) that node can not be a unique_ptr, as that would take away ownership from the tree object. In fact, having this variable refer to the root pointer in the tree is the right solution, as you don't want to mess around with ownership at this point, but just want to be able to get a grip on some node. But declaring it as a reference does not fit to the way you want to use it, because in C++ you can't re-seat a reference. What you do is you declare node to be just another name for this->root, so if you assign to node, you are overwriting your root node pointer. I am sure this is not what you intended. Instead, you want node to refer to a different object than it referred to before, so it needs to be something that references the root node and can be made to refer to something else. In C++, this means you want a pointer (as Jarod42 said in the comment). You have two choices at hand for the loop scanning the position where to insert:
Use a raw pointer to node instead of a unique_ptr to node. As you don't need ownership, a raw pointer to node is good enough: You can be sure the owning pointer (this->root) keeps alive as long a you need it, so there is no danger of the object disappearing.
Use a raw pointer to unique_ptr to node. This is essentially your approach, fixed to use a pointer instead of a reference.
As you say, you later need the unique_ptr to pass it to the balance function. If the balance function works out as it is now, and needs a unique_ptr argument, the decision is made: Having a copy of the raw pointer in node just doesn't do what you want, so you need the pointer-to-unique_ptr.
Do class objects declared on the stack have the same lifetime as other stack variables?
I have this code:
#include <stdio.h>
#include <vector>
using std::vector;
#include <string>
using std::string;
class Child;
class Parent
{
public:
Parent(string s) : name(s) { };
vector<Child> children;
string name;
};
class Child
{
public:
Child() { /* I need this for serialization */ };
Child(Parent *p) : parent(p) { };
Parent *parent;
};
Parent
family()
{
Parent p("John Doe");
int i;
printf("family:\n\tparent: 0x%x\n\ti: %x\n", &p, &i);
for (i = 0; i < 2; ++i)
p.children.push_back(Child(&p));
return p;
}
int
main(void)
{
Parent p = family();
printf("main:\n\tparent: 0x%x\n", &p);
for (unsigned int i = 0; i < p.children.size(); ++i)
printf
(
"\t\tchild[%d]: parent: 0x%x parent.name '%s'\n",
i,
p.children[i].parent,
p.children[i].parent->name.c_str()
);
return 0;
}
My questions:
In function family, is Parent p declared on the stack? From looking at the output, it would seem so
Each created Child goes on the stack too, right?
When I create each Child instance, I pass it a pointer to a stack variable. I imagine this is a big no-no, because stack variables are guaranteed to live only until the end of the function. After that the stack should get popped and the variables will be destroyed. Is this correct?
vector.push_back() passes arguments by reference, so at the end of the family function, p.children just contains references to the local variables, right?
Why is it all working? In main, why can I access the parent and each of its children? Is it all because the local variables from family are still intact and haven't been overwritten by some subsequent function call?
I think I'm misunderstanding where stuff lives in memory in C++. I'd really like to be pointed a resource that explains it well. Thanks in advance.
EDIT
Output from compiling the source and running:
misha#misha-K42Jr:~/Desktop/stackoverflow$ ./a.out
family:
parent: 0x2aa47470
i: 2aa47438
main:
parent: 0x2aa47470
child[0]: parent: 0x2aa47470 parent.name 'John Doe'
child[1]: parent: 0x2aa47470 parent.name 'John Doe'
It all works because vector makes copies of everything that you push_back. Your family function is also returning a copy, so even though the stack variable p goes out of scope and gets destroyed, the copy is valid.
I should point out that the Parent pointers retained by the Child objects will be invalid after the end of the family function. Since you didn't explicitly create a copy constructor in Child, one was generated for you automatically by the compiler, and it does a straight copy of the pointer; the pointer will point to an invalid object once p goes out of scope.
The Child objects that are in the vector survive for the reason that Mark Ransom pointed out, but the pointer to Parent * that each Child contains (which points to p) becomes invalid just as you expected.
If it appears to work, what likely happend is the compiler's optimizer inlined family(), and then combined the storage of main(){p} and family(){p} to avoid copying the returned object. This optimization would be likely even without inlining, but nearly certain with it.
It's easy to see why it would be allowed in this case, since your Parent class doesn't customize the copy constructor, but it's actually allowed regardless. The C++ standard makes special reference to return value optimization, and permits the compiler to pretend that a copy constructor has no side effects, even if it can't prove this.
To fix this, the Parent needs to be allocated on the heap, and some other provision would need to be made to free it. Assuming that no time-travel is involved (so that no object can become its own ancestor), this could be easily accomplished by using tr1::shared_ptr (or boost::shared_pointer for pre-TR1 compilers) for the pointer each child holds to its parent.
In function family, is Parent p declared on the stack? From looking at the output, it would seem so
Yes, that's right. However, since it is clear that p is returned by the function family, the compiler will use it to store the result instead of actually copying it into left-hand-side of Parent p = family();. In other words, it doesn't create the p in family() and then copies it because that would be wasteful. Instead, it creates the p in main() and uses it as p in family() to store the result directly (avoiding the useless copy).
Each created Child goes on the stack too, right?
No, std::vector dynamically allocates memory to store its elements (as indicated by the fact that the size can change at run-time). So the instances of Child that are pushed to the vector container are store in dynamically allocated memory (the Heap).
When I create each Child instance, I pass it a pointer to a stack variable. I imagine this is a big no-no, because stack variables are guaranteed to live only until the end of the function. After that the stack should get popped and the variables will be destroyed. Is this correct?
Yes that is correct. You should avoid this situation because it can be unsafe. One good way to avoid this and still have the capability of storing a pointer to the Parent in the Child object is to make the Parent non-copyable (making both copy-constructor and assignment operator private and without an implementation). This will have the effect that since a Parent cannot be copied and since the parent contains its children, the pointer to parent that the children have will never go invalid as long as the children are not destroyed (since they are destroyed along with their parent). This scheme would usually also come with a sort-of factory function for the Child objects and a private access on the Child's constructor granting friendship to the parent or static factory function. That way, it is also possible to prohibit a programmer from creating instances of Child that are not directly owned by the parent to which they are attached. Note also, that move-semantics and/or deep-copying can make the parent "copyable" or at least movable while keeping the children consistent with their parent.
vector.push_back() passes arguments by reference, so at the end of the family function, p.children just contains references to the local variables, right?
No, vector takes arguments by const reference, then possibly allocates additional storage for that object, and then places a copy of the argument into that new memory slot (placement new operator). So the p.children are objects (not references) and are contained in the vector (it is called a "container" after all).
Why is it all working? In main, why can I access the parent and each of its children? Is it all because the local variables from family are still intact and haven't been overwritten by some subsequent function call?
If you read my first answer, it becomes evident why this still works (but it might not work all the time).
I have objects which create other child objects within their constructors, passing 'this' so the child can save a pointer back to its parent. I use boost::shared_ptr extensively in my programming as a safer alternative to std::auto_ptr or raw pointers. So the child would have code such as shared_ptr<Parent>, and boost provides the shared_from_this() method which the parent can give to the child.
My problem is that shared_from_this() cannot be used in a constructor, which isn't really a crime because 'this' should not be used in a constructor anyways unless you know what you're doing and don't mind the limitations.
Google's C++ Style Guide states that constructors should merely set member variables to their initial values. Any complex initialization should go in an explicit Init() method. This solves the 'this-in-constructor' problem as well as a few others as well.
What bothers me is that people using your code now must remember to call Init() every time they construct one of your objects. The only way I can think of to enforce this is by having an assertion that Init() has already been called at the top of every member function, but this is tedious to write and cumbersome to execute.
Are there any idioms out there that solve this problem at any step along the way?
Use a factory method to 2-phase construct & initialize your class, and then make the ctor & Init() function private. Then there's no way to create your object incorrectly. Just remember to keep the destructor public and to use a smart pointer:
#include <memory>
class BigObject
{
public:
static std::tr1::shared_ptr<BigObject> Create(int someParam)
{
std::tr1::shared_ptr<BigObject> ret(new BigObject(someParam));
ret->Init();
return ret;
}
private:
bool Init()
{
// do something to init
return true;
}
BigObject(int para)
{
}
BigObject() {}
};
int main()
{
std::tr1::shared_ptr<BigObject> obj = BigObject::Create(42);
return 0;
}
EDIT:
If you want to object to live on the stack, you can use a variant of the above pattern. As written this will create a temporary and use the copy ctor:
#include <memory>
class StackObject
{
public:
StackObject(const StackObject& rhs)
: n_(rhs.n_)
{
}
static StackObject Create(int val)
{
StackObject ret(val);
ret.Init();
return ret;
}
private:
int n_;
StackObject(int n = 0) : n_(n) {};
bool Init() { return true; }
};
int main()
{
StackObject sObj = StackObject::Create(42);
return 0;
}
Google's C++ programming guidelines have been criticized here and elsewhere again and again. And rightly so.
I use two-phase initialization only ever if it's hidden behind a wrapping class. If manually calling initialization functions would work, we'd still be programming in C and C++ with its constructors would never have been invented.
Depending on the situation, this may be a case where shared pointers don't add anything. They should be used anytime lifetime management is an issue. If the child objects lifetime is guaranteed to be shorter than that of the parent, I don't see a problem with using raw pointers. For instance, if the parent creates and deletes the child objects (and no one else does), there is no question over who should delete the child objects.
KeithB has a really good point that I would like to extend (in a sense that is not related to the question, but that will not fit in a comment):
In the specific case of the relation of an object with its subobjects the lifetimes are guaranteed: the parent object will always outlive the child object. In this case the child (member) object does not share the ownership of the parent (containing) object, and a shared_ptr should not be used. It should not be used for semantic reasons (no shared ownership at all) nor for practical reasons: you can introduce all sorts of problems: memory leaks and incorrect deletions.
To ease discussion I will use P to refer to the parent object and C to refer to the child or contained object.
If P lifetime is externally handled with a shared_ptr, then adding another shared_ptr in C to refer to P will have the effect of creating a cycle. Once you have a cycle in memory managed by reference counting you most probably have a memory leak: when the last external shared_ptr that refers to P goes out of scope, the pointer in C is still alive, so the reference count for P does not reach 0 and the object is not released, even if it is no longer accessible.
If P is handled by a different pointer then when the pointer gets deleted it will call the P destructor, that will cascade into calling the C destructor. The reference count for P in the shared_ptr that C has will reach 0 and it will trigger a double deletion.
If P has automatic storage duration, when it's destructor gets called (the object goes out of scope or the containing object destructor is called) then the shared_ptr will trigger the deletion of a block of memory that was not new-ed.
The common solution is breaking cycles with weak_ptrs, so that the child object would not keep a shared_ptr to the parent, but rather a weak_ptr. At this stage the problem is the same: to create a weak_ptr the object must already be managed by a shared_ptr, which during construction cannot happen.
Consider using either a raw pointer (handling ownership of a resource through a pointer is unsafe, but here ownership is handled externally so that is not an issue) or even a reference (which also is telling other programmers that you trust the referred object P to outlive the referring object C)
A object that requires complex construction sounds like a job for a factory.
Define an interface or an abstract class, one that cannot be constructed, plus a free-function that, possibly with parameters, returns a pointer to the interface, but behinds the scenes takes care of the complexity.
You have to think of design in terms of what the end user of your class has to do.
Do you really need to use the shared_ptr in this case? Can the child just have a pointer? After all, it's the child object, so it's owned by the parent, so couldn't it just have a normal pointer to it's parent?
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.