
Hello, I've trouble with the follwong snippet: #include <iostream> #include <boost/shared_ptr.hpp> struct A { A(const char* n) : name(n) { } const char* name; }; struct B : public A { B(const char* n) : A(n) { std::cout << "construct " << name << std::endl; } ~B() { std::cout << "destruct " << name << std::endl; } }; struct BaseC { virtual void set(const boost::shared_ptr<A>& ptr) = 0; }; struct C : public BaseC { C() : b( new B("C::b") ) { } void set(const boost::shared_ptr<A>& ptr) { b.swap( boost::shared_static_cast<B>( ptr ) ); // L21 } void print() { std::cout << b->name << std::endl; } boost::shared_ptr<B> b; }; using namespace std; int main() { boost::shared_ptr<A> b( new B("b") ); C c; c.print(); c.set( b ); c.print(); } t.cc: In member function `virtual void C::set(const boost::shared_ptr<A>&)': t.cc:21: no matching function for call to `boost::shared_ptr<B>::swap(boost::shared_ptr<B>)' /usr/include/boost/shared_ptr.hpp:234: candidates are: void boost::shared_ptr<T>::swap(boost::shared_ptr<T>&) [with T = B] I did try boost::shared_polymorphic_cast to get a std::bad_cast exception - but it doesn't compile too. How can get it working? Thanks Olaf

From: "Olaf Petzold" <yg-boost-users@gmane.org>
struct C : public BaseC { C() : b( new B("C::b") ) { } void set(const boost::shared_ptr<A>& ptr) { b.swap( boost::shared_static_cast<B>( ptr ) ); // L21 } void print() { std::cout << b->name << std::endl; } boost::shared_ptr<B> b; };
Why not simply b = boost::shared_static_cast<B>( ptr ); or b = boost::shared_polymorphic_cast<B>( ptr ); ?

Thank you,
struct C : public BaseC { C() : b( new B("C::b") ) { } void set(const boost::shared_ptr<A>& ptr) { b.swap( boost::shared_static_cast<B>( ptr ) ); // L21 } void print() { std::cout << b->name << std::endl; } boost::shared_ptr<B> b; };
Why not simply
b = boost::shared_static_cast<B>( ptr );
or
b = boost::shared_polymorphic_cast<B>( ptr );
I want to swap the pointers inside for further use (for saving the old ptr contents and restoring for circumstances - clone() may be one way before set() it but has overhead). Regards Olaf

void set(const boost::shared_ptr<A>& ptr) { b.swap( boost::shared_static_cast<B>( ptr ) ); // L21 } Why not simply
b = boost::shared_static_cast<B>( ptr ); I want to swap the pointers inside for further use (for saving the old ptr contents and restoring for circumstances
If you actually want to swap b and ptr, then shouldn't ptr be declared non-const? Tanton

From: "Olaf Petzold" <yg-boost-users@gmane.org>
Thank you,
struct C : public BaseC { C() : b( new B("C::b") ) { } void set(const boost::shared_ptr<A>& ptr) { b.swap( boost::shared_static_cast<B>( ptr ) ); // L21 } void print() { std::cout << b->name << std::endl; } boost::shared_ptr<B> b; };
Why not simply
b = boost::shared_static_cast<B>( ptr );
or
b = boost::shared_polymorphic_cast<B>( ptr );
I want to swap the pointers inside for further use (for saving the old ptr contents and restoring for circumstances - clone() may be one way before set() it but has overhead).
You can't swap() two pointers (objects, in general) of different types, and you can't swap() with a temporary (which is what the cast returns.) One possible way is to change set() to return the old value: shared_ptr<A> set(shared_ptr<A> const & p) { shared_ptr<A> tmp(b); b = boost::shared_polymorphic_cast<B>(p); return tmp; } You can keep the old interface (minus the "const" on the parameter) if you want, but the swapping needs to be done "by hand": void set(shared_ptr<A> & p) { shared_ptr<A> tmp(b); b = boost::shared_polymorphic_cast<B>(p); p = tmp; }

Thanks for answers, the const ptr was a fault. Well, the following example shows the problem in detail: ----8<---- #include <iostream> #include <boost/shared_ptr.hpp> struct Spec { Spec(const char* n) : m_name(n) { } void member() const { std::cout << "Hold " << m_name << std::endl; } const char* m_name; }; struct SpecLP : public Spec { SpecLP(const char* n) : Spec(n) { std::cout << "construct " << m_name << std::endl; } ~SpecLP() { std::cout << "destruct " << m_name << std::endl; } }; struct SpecHP : public Spec { SpecHP(const char* n) : Spec(n) { std::cout << "construct " << m_name << std::endl; } ~SpecHP() { std::cout << "destruct " << m_name << std::endl; } }; struct Doc { virtual ~Doc() { } virtual void set(boost::shared_ptr<Spec>& ptr) = 0; }; struct LpDoc : public Doc { LpDoc() : m_lp( new SpecLP("LpDoc::lp") ) { } void set(boost::shared_ptr<Spec>& spec) { // m_lp = boost::shared_static_cast<SpecLP>( spec ); m_lp = boost::shared_polymorphic_cast<SpecLP>( spec ); } void print() { m_lp->member(); } boost::shared_ptr<SpecLP> m_lp; }; struct HpDoc : public Doc { HpDoc() : m_hp( new SpecHP("HpDoc::hp") ) { } void set(boost::shared_ptr<Spec>& spec) { // m_hp = boost::shared_static_cast<SpecHP>( spec ); m_hp = boost::shared_polymorphic_cast<SpecHP>( spec ); } void print() { m_hp->member(); } boost::shared_ptr<SpecHP> m_hp; }; int main() { boost::shared_ptr<Spec> lp( new SpecLP("lp") ); boost::shared_ptr<Spec> hp( new SpecHP("hp") ); LpDoc doc; std::cout << "Case 1:\n"; doc.print(); doc.set( lp ); // is O.K. doc.print(); std::cout << "Case 2:\n"; try { doc.print(); doc.set( hp ); // should throw doc.print(); } catch(const std::bad_alloc& e) { std::cerr << "Exception \"" << e.what() << "\" catched\n"; } } ---->8---- It doesn't compile with shared_ptr. Imho is the polymorph code correct expect the pointer problem. Thanks Olaf

From: "Olaf Petzold" <yg-boost-users@gmane.org>
Thanks for answers,
the const ptr was a fault.
Well, the following example shows the problem in detail:
Two errors. First, Spec is not a polymorphic type - add a virtual function (destructor, for instance) to enable dynamic_cast / polymorphic_cast. Second, the exception thrown is std::bad_cast, not std::bad_alloc.

Peter Dimov wrote:
From: "Olaf Petzold" <yg-boost-users@gmane.org>
Thanks for answers,
the const ptr was a fault.
Well, the following example shows the problem in detail:
Two errors. First, Spec is not a polymorphic type - add a virtual function (destructor, for instance) to enable dynamic_cast / polymorphic_cast. Second, the exception thrown is std::bad_cast, not std::bad_alloc.
Oh dear, it's too hot here ... It's working now - thanks a lot. Olaf
participants (3)
-
Olaf Petzold
-
Peter Dimov
-
Tanton Gibbs