shared_ptr and shared_from_this
I have an interpreter that uses a visitor pattern while performing a reduction of the program tree. As part of the visitor pattern, each class that can be a node in the tree must respond to: virtual void accept(Visitor& v); where each node then implements by calling visitor with itself using the proper type. The function calls in visitor are like: void visit(shared_ptr<Node> node); void visit(shared_ptr<Type> node); etc. (where Type is a descendant of node BTW). Normally with the visitor pattern (GOF style in this case), the implementation of accept is simply: void Node::accept(Visitor &v) { v.visit(this); } I've tried adding enable_shared_from_this<...> as a superclass of my nodes, and returning shared_from_this(), which works in some cases, but in others just seems to hang. These occur in classes that are a little more complex. For example, I have a TypeTemplate<T> class that wraps to underlying types TypeTemplate<int>, TypeTemplate<float>, TypeTemplate<etc>. I've tried adding enable_shared_from_this<TypeTemplate<T> >, and then having an implmentation void TypeTemplate<T>::accept(Visitor &v) { v.visit(enable_shared_from_this<TypeTemplate<T> >::shared_from_this()); } but it just hangs on both vc7.1 on windows and Xcode on OS X. (I had to add the extra scoping because I got complaints that "shared_from_this() was ambiguous in multiple inheritance.") I read in some past postings that the shared_from_this template doesn't work so well for complex class hierarchies, and I am wondering if I am running into that. I was thinking of putting my own internal_weak_ptr into the classes, but was confused by some of the examples I have seen. Most of them seem to reference a static function create() which instantiates the weak_ptr, and returns a shared_ptr<X>. When I consider my situation: shared_ptr<Node> aNode(new Node(...)); Visitor v; aNode->accept(v); How does the accept implementation return a shared_ptr that is linked with aNode? I've looked through the enable_shared_from_this implementation, and can't figure out how it is supposed to work. even if I return shared_from_this(), I'm not sure now that is linked to aNode. Does everything have to go through a factory like create()? Sorry for the long rambling e-mail. I hope it makes sense what I am trying to do. Cheers, tim
Timothy Ritchey wrote:
I have an interpreter that uses a visitor pattern while performing a reduction of the program tree. As part of the visitor pattern, each class that can be a node in the tree must respond to:
virtual void accept(Visitor& v);
where each node then implements by calling visitor with itself using the proper type. The function calls in visitor are like:
void visit(shared_ptr<Node> node); void visit(shared_ptr<Type> node); etc.
(where Type is a descendant of node BTW).
Interesting. Why do you need to pass a shared_ptr to the visitor?
Normally with the visitor pattern (GOF style in this case), the implementation of accept is simply:
void Node::accept(Visitor &v) { v.visit(this); }
I've tried adding enable_shared_from_this<...> as a superclass of my nodes, and returning shared_from_this(), which works in some cases, but in others just seems to hang. These occur in classes that are a little more complex. For example, I have a TypeTemplate<T> class that wraps to underlying types TypeTemplate<int>, TypeTemplate<float>, TypeTemplate<etc>. I've tried adding enable_shared_from_this<TypeTemplate<T> >, and then having an implmentation
void TypeTemplate<T>::accept(Visitor &v) { v.visit(enable_shared_from_this<TypeTemplate<T>
::shared_from_this()); }
but it just hangs on both vc7.1 on windows and Xcode on OS X. (I had to add the extra scoping because I got complaints that "shared_from_this() was ambiguous in multiple inheritance.")
shared_from_this() shouldn't hang; can you simplify this down to a minimal example? Since shared_from_this() is ambiguous, I take it that your class has several enable_shared_from_this base classes. This doesn't work; at most one of them will be initialized properly, the rest will (should) just throw bad_weak_ptr. You'll need to try to eliminate the multiple enable_shared_from_this bases. This can typically be done by following the "non-leaf classes should be abstract" advice. IOW: class Node: public enable_shared_from_this<Node> {}; class Type: public Node, public enable_shared_from_this<Type> {}; needs to be refactored as: class AbstractNode { /* pure virtuals */ }; class AbstractType: public AbstractNode { /* pure virtuals */ }; class Node: public AbstractNode, public enable_shared_from_this<Node> {}; class Type: public AbstractType, public enable_shared_from_this<Type> {}; This is the best advice I can offer without more information. :-) I hope that it helps.
Peter, On Oct 22, 2004, at 11:03 AM, Peter Dimov wrote:
Why do you need to pass a shared_ptr to the visitor?
That is a very good question. I had a couple of motivations: first, I thought I read somewhere that it was generally a good idea to make interfaces take shared_ptrs in order to help with issues of ownership. Also, the visitor is being used to interpret a program tree, which involves a mixture of singleton functors as well as normal program constructs that are free to be destroyed once they are done. By taking shared_ptrs, it greatly simplifies the management of nodes when performing a reduction on the tree. That being said, I suppose I could have taken the pointers, and then just had local shared_ptrs in each function.
You'll need to try to eliminate the multiple enable_shared_from_this bases. This can typically be done by following the "non-leaf classes should be abstract" advice. IOW:
Thanks for the advice. I was able to get it working once I made all non-leaf nodes abstract, and did a little refactoring of the tree. Thanks again for the help. Cheers, tim
participants (2)
-
Peter Dimov
-
Timothy Ritchey