#include <iostream>
#include <set>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp> using namespace std;
using namespace boost;struct NodeImpl;
NodeImpl* NodeImpl_Create(int id);
struct Node {
Node(int id) : pimpl_(NodeImpl_Create(id)) { }
Node(const Node& n) : pimpl_(n.pimpl_) { }
Node() { }
void Connect(const Node& n);
private:
shared_ptr<NodeImpl> pimpl_;
friend bool operator<(const Node& n1, const Node& n2);
}; bool operator<(const Node& n1, const Node& n2) {
return n1.pimpl_ < n2.pimpl_;
} struct NodeImpl : noncopyable {
NodeImpl(int id) : id_(id) { cout << id_ << " lives\n"; }
~NodeImpl() { cout << id_ << " dies\n"; }
private:
int id_;
set<Node> nodes_;
friend struct Node;
};NodeImpl* NodeImpl_Create(int id) { return new NodeImpl(id); }
void Node::Connect(const Node& n) {
pimpl_->nodes_.insert(n);
} int main() {
{
Node n1(1); {
Node n2(2), n3(3), n4(4); n1.Connect(n2);
n2.Connect(n2);
n3.Connect(n3);
n4.Connect(n4);
} cout << "n1 points to the cluster {n2, n3, n4}\n";
}cout << "n2, n3, n4 remain alive. That sucks.\n";
void free_unreachable_objects();
free_unreachable_objects(); cout << "Done\n";
}Running it, you'll see that free_unreachable_objects() fails to find/delete the dangling n2, n3 and n4.
Investigating, I determined that the reason is this: in order for sp_collector to do its magic, it must always be the case that shared_ptr's are contained directly within things pointed to by other shared_ptr's. In my example, this invariant is violated, because I'm storing Node's in a set. A Node contains a shared_ptr. You can have a Node directly in a NodeImpl, no problem. But you can't have a Node in a disembodied bit of memory, as produced by set to store its contents.
In the following modification, I change NodeImpl so that it contains the the shared_ptr's directly:
26a27,28
> const int MAX_NODES = 10;
>
28c30
< NodeImpl(int id) : id_(id) { cout << id_ << " lives\n"; }
---
> NodeImpl(int id) : id_(id), nnodes_(0) {
cout << id_ << " lives\n"; }
32c34,35
< set<Node> nodes_;
---
> Node nodes_[MAX_NODES];
> int nnodes_;
39c42,43
< pimpl_->nodes_.insert(n);
---
> if (pimpl_->nnodes_ < MAX_NODES)
> pimpl_->nodes_[pimpl_->nnodes_++] = n;Now, sp_collector succeeds in finding & deleting the stale objects. Unfortunately, it means that I don't get to use the standard containers. All I get to use is a rotten array. Boo hoo!
And so, sp_collector suffers the same problem as shared_cyclic_ptr, and requires the same remedy: that is, it is necessary to be able to "tag" a container as being one which might hold "internal" shared_ptr's.
Any interest in modifying shared_ptr to support something like this?
- Chuck
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
