I'm trying to implement the Observer pattern, but i don't want observers being responsible for my program safety by maintaining the reference list in ObservableSubject.
Meaning that when the Observer object lifetime ends, I dont want to explicitly call ObservervableSubject::removeObserver(&object).
I have come up with an idea to use use pointer references in ObservableSubject.
My question are: Is implementation described above and attempted below possible?
And what is happening in my program, how do i prevent dereferencing trash?
Apriori excuse: This is an attempt at understanding C++, not something that should have actual use or be prefered over other implementations.
My solution attempt:
// Example program
#include <iostream>
#include <string>
#include <vector>
class ObserverInterface {
public:
virtual ~ObserverInterface() {};
virtual void handleMessage() = 0;
};
class ObservableSubject
{
std::vector<std::reference_wrapper<ObserverInterface*>> listeners;
public:
void addObserver(ObserverInterface* obs)
{
if (&obs)
{
// is this a reference to the copied ptr?
// still, why doesnt my guard in notify protect me
this->listeners.push_back(obs);
}
}
void removeObserver(ObserverInterface* obs)
{
// todo
}
void notify()
{
for (ObserverInterface* listener : this->listeners)
{
if (listener)
{
listener->handleMessage();
}
}
}
};
class ConcreteObserver : public ObserverInterface {
void handleMessage()
{
std::cout << "ConcreteObserver: I'm doing work..." << std::endl;
}
};
int main()
{
ObservableSubject o;
{
ConcreteObserver c;
o.addListener(&c);
}
o.notify();
std::cin.get();
}
Line in ObservableSubject::notify() : Listener->handleMessage() throws the following exception:
Exception thrown: read access violation.
listener->**** was 0xD8BF48B. occurred
Your program has undefined behavior.
ObservableSubject o;
{
ConcreteObserver c;
o.addListener(&c); // Problem
}
c gets destructed when the scope ends. You end up storing a stale pointer in the list of listeners of o.
You can resolve the problem by defining c in the same scope as o or by using dynamically allocated memory.
ObservableSubject o;
ConcreteObserver c;
o.addListener(&c);
or
ObservableSubject o;
{
ConcreteObserver* c = new ConcreteObserver;
o.addListener(c);
}
When you use dynamically allocated memory, the additional scope is not useful. You might as well not use it.
ObservableSubject o;
ConcreteObserver* c = new ConcreteObserver;
o.addListener(c);
If you choose to use the second approach, make sure to deallocate the memory. You need to add
delete c;
before the end of the function.
Update, in response to OP's comment
You said:
Maybe i wasn't clear. Solving the lifetime/stale pointer problem was the intention of my solution. I know i have no problems if i have properly managed lifetime, or if i add detachObserver option on Observer destruction. I want to somehow be able to tell from the ObservableSubject if his list of Observers was corrupted, without the Observer explicitly telling that.
Since dereferencing an invalid pointer is cause for undefined behavior, it is essential that you track the lifetime of observers and make sure to update the list of observers when necessary. Without that, you are courting undefined behavior.
Note, I don't recommend the following approach, but I think it meets your requirements. You have a duplicated observer list. One is under control of the Observers, and the other, using weak pointers, is handled by the Observable object.
Make the Observer constructors private and use an ObserverFactory (which is their friend) to obtain a std::shared_ptr<Observer>. The factory has a map from raw pointers to reference wrappers to the associated shared pointer.
The listeners list becomes std::vector<std::weak_ptr<Observer>>. On list traversal, you try to lock the weak_ptr; if it succeeds, handle the message; if it fails, that is, you get nullptr, remove the weak pointer from the list.
When the listener no longer wants to listen, it tells the Factory to do a reset on its shared pointer and remove from the map. This step is rather ugly, as it is just a fancy delete this, normally a code smell.
I believe you can also do this with std::shared_from_this.
The plan is you move the maintenance away from the ObservableSubject back into the Observers.
// is this a reference to the copied ptr?
Yes, it is. It invokes undefined behaviour because the obs pointer variable goes out of scope at the end of the function, resulting in a dangling reference.
The whole idea doesn’t gain you anything. Even if you make the ref-to-pointer approach work correctly, you are depending on one thing: That that exact pointer variable is set to nullptr once the object dies. Essentially that’s the same problem as ensuring that no dangling pointers are held in listeners.
For a heap object: How do you make sure that nobody deletes the object through a different pointer? Or forgets to null the registered pointer? It’s even worse for stack objects like in your example. The object goes out of scope and dies automatically. There is no opportunity to null anything unless you introduce an additional pointer variable that you’d have to manage manually.
You could consider two general alternatives to your approach:
Make the relation bidirectional. Then whoever dies first (observable or observer) can notify the other party abouts its death in the destructor.
If you don’t like the bidirectionality a central, all-knowing orchestrator that decouples oberservers and observables works, too. Of course that introduces some kind of global state.
Real-life implementations usually go in the general direction of leveraging C++ destructors for deregistration. Have a look at Qt’s signal/slot mechanism, for example.
Related
Suppose that we have a STL container with some objects, and these objects can post functions to a queue to be executed later. But before these functions get executed, the container gets modified in such a way that pointers pointing to that object are invalidated. Let me illustrate with an example:
#include <vector>
#include <functional>
class Class_A
{
public:
std::function<void()> getFunctionToRunLater()
{
return [this] () { somethingToDo(); moreThingsToDo(); };
// Returns a lambda function that captures the this pointer,
// so it can access the object's methods and variables.
}
void somethingToDo();
void moreThingsToDo();
}
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
pendingFunction();
}
Everything fine, right? We get a function the object wants to run and, after some logic, we execute that function. This represents posting functions to a queue and them execute all functions in the queue. But now look at this one:
int main()
{
std::vector<Class_A> vec;
vec.push_back(Class_A());
std::function<void()> pendingFunction = vec.back().getFunctionToRunLater();
// More code...
vec.reserve(1000);
// This will surely reallocate the vector, invalidating all pointers.
pendingFunction();
// And now my program is going straight down to hell, right?
}
Is my assumption correct? What will happen if the lambda doesn't capture anything at all, will the program still be logically broken? And what about if the lambda doesn't capture the this pointer, but rather some other class field specifically?
The existing answer already mentions that the pointer can be invalidated. One way to avoid the problem is, as already mentioned, changing the ownership of *this by either shared_ptr, unique_ptr or a copy. However, this comes at extra cost (dynamic allocation or extra copy) and sometimes is simply not possible (non-copyable types).
Instead, I would suggest a design that doesn't lead to this problem in the first place, i.e. not making the this pointer part of the lambda's state. Take the object as a parameter:
std::function<void(Class_A&)> getFunctionToRunLater()
{
return [] (Class_A& obj) { obj.somethingToDo(); obj.moreThingsToDo(); };
}
If copying the object is a possibility, then you can capture *this by value: (requires C++17)
return [*this] { somethingToDo(); moreThingsToDo(); }
This copies the whole object into the closure to avoid out-of-lifetime access to the original object.
Yes this program is likely to have problems. C++ does not protect you from invalidating pointers, and as you've highlighted the objects in your vector will potentially move address when the vector resizes, which will cause problems if you try to run your lambda.
You will probably be unable to compile the program without capturing this. You will also end up with issues if you try to capture references or pointers to any part of your object without being sure the memory being pointed at will not move.
It pays to be cautious, as a program like this is not guaranteed to crash even if you have a bug, as the old data may still exist in memory even when your vector resizes. So if you try capturing this and don't see any issues at runtime it does not mean that your program is correct.
For a straight forward solution, I'd look at allocating your objects on the heap using one of the smart pointer types such as std::unique_ptr or std::shared_ptr.
So to illustrate my question I have made an example:
#include <iostream>
using namespace std;
struct A
{
void doSomething (){
cout << "Something\n";
}
};
struct B
{
A a;
A *getA ()
{
return &a;
}
};
int
main ()
{
B *b = new B ();
A *a = b->getA ();
// POINT 1
if (nullptr != a)
{
a->doSomething ();
}
delete b;
b = nullptr;
// POINT 2
if (nullptr != a)
{
a->doSomething ();
}
return 0;
}
This compiles and runs without errors on my machine, but if you inspect the code, really there is a problem of a dangling pointer on the lines following the comment marked "POINT 2".
Since b was deleted, then a is now invalid (since it was deleted by dtor of b).
So I could use a shared pointer to remedy this, but that would keep the instance of a around even after b was deleted, and also I would not be able to allocate a on the stack. These are two things I want to avoid. Instead I simply want to know if a is still valid.
I could also have used a unique pointer but then I could only have one single instance of a which is not what I want either, I want many copies of the pointer to a.
So is there some existing pointer/reference type that would allow me to do this? Are there any reason why this is a good/bad idea?
You have just discovered the wonders of ownership semantics :)
How to solve this problem depends on the design of your application: what you need and what you are trying to achieve.
In this case, if you really want to share ownership of an object, use std::shared_ptr which keeps a reference count of how many pointers are left, so that the last deletes the object; possibly std::weak_ptr if you only need to check if the object is still alive but don't want to keep it alive longer than needed.
However, do note that (ab)using shared pointers may be a sign of a bad design.
By the way, your A a; member is not allocated in the stack (i.e. the title is wrong).
Only viable solution using standard library that come in mind is to use std::weak_ptr() - it will allow to check object validity without holding it's ownership. That comes with price - you have to maintain ownership of it with std::shared_ptr. Though it is possible to create std::shared_ptr to an object with automatic storage duration and noop deleter I would do that only if I really need that as such method is error prone and defeats the purpose of a smart pointer.
The best way is to not expose a.
Your B is the interface. Give it the functions you need to perform. Have it go on to invoke whatever it needs to invoke on the a in order to make that happen.
Then remove getA(), and make a private.
Now it's completely encapsulated and the calling scope cannot arse around with it like this!
No need for pointers or dynamic allocation; just good, old-fashioned OOP.
This question already has answers here:
How can I determine if a C++ object has been deallocated?
(6 answers)
Closed 4 years ago.
Consider this program:
int main()
{
struct test
{
test() { cout << "Hello\n"; }
~test() { cout << "Goodbye\n"; }
void Speak() { cout << "I say!\n"; }
};
test* MyTest = new test;
delete MyTest;
MyTest->Speak();
system("pause");
}
I was expecting a crash, but instead this happened:
Hello
Goodbye
I say!
I'm guessing this is because when memory is marked as deallocated it isn't physically wiped, and since the code references it straight away the object is still to be found there, wholly intact. The more allocations made before calling Speak() the more likely a crash.
Whatever the reason, this is a problem for my actual, threaded code. Given the above, how can I reliably tell if another thread has deleted an object that the current one wants to access?
There is no platform-independent way of detecting this, without having the other thread(s) set the pointer to NULL after they've deleted the object, preferably inside a critical section, or equivalent.
The simple solution is: design your code so that this can't occur. Don't delete objects that might be needed by other threads. Clear up shared resource only once it's safe.
I was expecting a crash, but instead
this happened:
That is because Speak() is not accessing any members of the class. The compiler does not validate pointers for you, so it calls Speak() like any other function call, passing the (deleted) pointer as the hidden 'this' parameter. Since Speak() does not access that parameter for anything, there is no reason for it to crash.
I was expecting a crash, but instead this happened:
Undefined Behaviour means anything can happen.
Given the above, how can I reliably tell if another thread has deleted an object that the current one wants to access?
How about you set the MyTest pointer to zero (or NULL). That will make it clear to other threads that it's no longer valid. (of course if your other threads have their own pointers pointing to the same memory, well, you've designed things wrong. Don't go deleting memory that other threads may use.)
Also, you absolutely can't count on it working the way it has. That was lucky. Some systems will corrupt memory immediately upon deletion.
Despite it's best to improve the design to avoid access to a deleted object, you can add a debug feature to find the location where you access deleted objects.
Make all methods and the destructor virtual.
Check that your compiler creates an object layout where the pointer to
the vtable is in front of the object
Make the pointer to the vtable invalid in the destructor
This dirty trick causes that all functions calls reads the address where the pointer points to and cause a NULL pointer exception on most systems. Catch the exception in the debugger.
If you hesitate to make all methods virtual, you can also create an abstract base class and inherit from this class. This allows you to remove the virtual function with little effort. Only the destructor needs to be virtual inside the class.
example
struct Itest
{
virtual void Speak() = 0;
virtual void Listen() = 0;
};
struct test : public Itest
{
test() { cout << "Hello\n"; }
virtual ~test() {
cout << "Goodbye\n";
// as the last statement!
*(DWORD*)this = 0; // invalidate vtbl pointer
}
void Speak() { cout << "I say!\n"; }
void Listen() { cout << "I heard\n"; }
};
You might use reference counting in this situation. Any code that dereferences the pointer to the allocated object will increment the counter. When it's done, it decrements. At that time, iff the count hits zero, deletion occurs. As long as all users of the object follow the rules, nobody access the deallocated object.
For multithreading purposes I agree with other answer that it's best to follow design principles that don't lead to code 'hoping' for a condition to be true. From your original example, were you going to catch an exception as a way to tell if the object was deallocated? That is kind of relying on a side effect, even if it was a reliable side effect which it's not, which I only like to use as a last resort.
This is not a reliable way to "test" if something has been deleted elsewhere because you are invoking undefined behavior - that is, it may not throw an exception for you to catch.
Instead, use std::shared_ptr or boost::shared_ptr and count references. You can force a shared_ptr to delete it's contents using shared_ptr::reset(). Then you can check if it was deleted later using shared_ptr::use_count() == 0.
You could use some static and runtime analyzer like valgrind to help you see these things, but it has more to do with the structure of your code and how you use the language.
// Lock on MyTest Here.
test* tmp = MyTest;
MyTest = NULL;
delete tmp;
// Unlock MyTest Here.
if (MyTest != NULL)
MyTest->Speak();
One solution, not the most elegant...
Place mutexes around your list of objects; when you delete an object, mark it as null. When you use an object, check for null. Since access is serialized, you'll have a consistent operation.
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.