Boost logo

Boost Users :

Subject: [Boost-users] Help with custom smart pointer const correctness
From: Dominique Devienne (ddevienne_at_[hidden])
Date: 2009-04-15 17:16:53


Given the class design below, and the ObjectPtr smart pointer
implementation, I can't instantiate ObjectPtr<T> with T = const Car
because a const Car returns a shared_ptr<const CarIdent> from the
ident() methods, not a shared_ptr<CarIdent> as currently implemented
(see compile error at the end of this post. VS2005).

>From my very limited meta-programming experience, I'm guessing I need
to fix the current typedef shared_ptr<ident_type> ident_ptr; in
ObjectPtr to somehow use MPL to "return" shared_ptr<typename
T::ident_type const> given a const T, and shared_ptr<typename
T::ident_type> given a T, but I don't know how to do that yet.

If someone would be kind enough to point me in the right direction,
I'd appreciate. Thanks, --DD

#include <boost/static_assert.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/cast.hpp>

#include <string>

using namespace std;
using namespace boost;

class Object;
class Ident {
public:
    Object* object() const { return object_; }

protected:
    Ident() : object_(0) {}
    ~Ident() {}

    friend class Object;
    void set_object(Object* e);

private:
    Object* object_;
};
typedef shared_ptr<Ident> IdentPtr;
typedef shared_ptr<const Ident> ConstIdentPtr;

class Object {
public:
    ConstIdentPtr ident() const { return ident_; }
    const IdentPtr& ident() { return ident_; }

protected:
    Object(shared_ptr<Ident> ident) : ident_(ident) {
ident_->set_object(this); }
    virtual ~Object() { ident_->set_object(0); }

private:
    shared_ptr<Ident> ident_;
};

void Ident::set_object(Object* obj) {
    BOOST_ASSERT((!object_ && obj) || (object_ && !obj));
    BOOST_ASSERT(!obj || obj->ident().get() == this);
    object_ = obj;
}

template <class T> shared_ptr<typename T::ident_type> ident_of(T* t) {
    BOOST_STATIC_ASSERT((is_base_of<Object, T>::value));
    return static_pointer_cast<typename T::ident_type>(t->ident());
}
template <class T> shared_ptr<typename T::ident_type const>
ident_of(const T* t) {
    BOOST_STATIC_ASSERT((is_base_of<Object, T>::value));
    return static_pointer_cast<typename T::ident_type const>(t->ident());
}

template <class T> class ObjectPtr {
public:
    typedef T object_type; // TODO remove constness
    typedef typename T::ident_type ident_type;
    typedef shared_ptr<ident_type> ident_ptr; // TODO: make const correct

public:
    // this Ctor fails to compile if passing a const Car for example.
    // TODO: figure out (MPL? enable_if?) the correct ident_ptr type
    // based on the constness of T
    explicit ObjectPtr(T* obj) : ident_(ident_of(obj)) {}

    T* get() {
        return polymorphic_downcast<T*>(ident_->object());
    }
    T* operator->() { get(); }
    T& operator*() { *get(); }

    ident_ptr ident() const {
        return ident_;
    }

    // TODO: Safe-Bool idiom
    // TODO: implicit conversion from ObjectPtr<T> to ObjectPtr<const T>?

private:
    ident_ptr ident_;
};

struct CarIdent : public Ident {
    string make, model;
    CarIdent(const string& make, const string& model) : make(make),
model(model) {}
};

class Car : public Object {
public:
    typedef CarIdent ident_type;

    Car(const string& make, const string& model)
    : Object(shared_ptr<CarIdent>(new CarIdent(make, model)))
    {}
};

void const_correct_smart_ptr(int /*argc*/, const char* /*argv*/[]) {
    ObjectPtr<Car> z(new Car("Nissan", "350Z"));
    ident_of(z.get())->model = "370Z"; // TODO: fix ident_of for smart
pointers to avoid .get()

    // This fails to compile with: error C2664:
    // 'boost::shared_ptr<T>::shared_ptr(const boost::shared_ptr<T> &)' :
    // cannot convert parameter 1 from 'boost::shared_ptr<const
Car::ident_type>'
    // to 'const boost::shared_ptr<CarIdent> &'
    // instantiated from explicit ObjectPtr(T* obj) : ident_(ident_of(obj)) {}

    ObjectPtr<const Car> zz(new Car("Ford", "Mustang"));
}


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net