Re: [Boost-users] [variant] not copy-constructable

From: Felipe Magno de Almeida [mailto:felipe.m.almeida@gmail.com]
What I wanted is a vector of variant<object1, object2> and I dont want object1 and object2 to be copied because it is expensive. But Im not figuring out how to do this... tried boost::ref either with no success... :/
Boost.Smart_ptr (http://www.boost.org/libs/smart_ptr/smart_ptr.htm) can help: use boost::shared_ptr, which is a reference-counted smart pointer. typedef boost::variant<object1,object2> variant_type; std::vector<boost::shared_ptr<variant_type> > vec; boost::shared_ptr<variant_type> v(new variant_type(object1())); vec.push_back(v); // No copying of the variant Bjorn Karlsson

On 7/12/05, Bjorn.Karlsson@readsoft.com <Bjorn.Karlsson@readsoft.com> wrote:
From: Felipe Magno de Almeida [mailto:felipe.m.almeida@gmail.com]
Boost.Smart_ptr (http://www.boost.org/libs/smart_ptr/smart_ptr.htm) can help: use boost::shared_ptr, which is a reference-counted smart pointer.
typedef boost::variant<object1,object2> variant_type;
std::vector<boost::shared_ptr<variant_type> > vec; boost::shared_ptr<variant_type> v(new variant_type(object1())); vec.push_back(v); // No copying of the variant
Is that what I needed was owning semantics... Like ptr_container for STL containers. But I think that isnt anything like that yet in boost... I will go with shared_ptr for now then. Or maybe intrusive_ptr.
Bjorn Karlsson
Thanks. Felipe. -- Felipe Magno de Almeida Developer from synergy and Computer Science student from State University of Campinas(UNICAMP). Unicamp: http://www.ic.unicamp.br Synergy: http://www.synergy.com.br "There is no dark side of the moon really. Matter of fact it's all dark."

<Bjorn.Karlsson@readsoft.com> wrote in message news:3D8559AE95B4D611B02C0002557C6C8B01A1AB75@STH-EXCH...
From: Felipe Magno de Almeida [mailto:felipe.m.almeida@gmail.com]
What I wanted is a vector of variant<object1, object2> and I dont want object1 and object2 to be copied because it is expensive. But Im not figuring out how to do this... tried boost::ref either with no success... :/
Funny I had the same problem just a few weeks ago...
Boost.Smart_ptr (http://www.boost.org/libs/smart_ptr/smart_ptr.htm) can help: use boost::shared_ptr, which is a reference-counted smart pointer.
typedef boost::variant<object1,object2> variant_type;
std::vector<boost::shared_ptr<variant_type> > vec; boost::shared_ptr<variant_type> v(new variant_type(object1())); vec.push_back(v); // No copying of the variant
I'm afraid this is not perfect. Copy will still occur when creating the variant. The variant's constructor copies the parameter into its own storage. It's just how it works. If object1/object2 were non-copyable, then you'll see that this code doesn't compile. The solution I found starts with something similar to this, but slightly different. Instead of: typedef boost::variant<object1,object2> variant_type; std::vector<boost::shared_ptr<variant_type> > vec; I wrote: typedef boost::variant<boost::shared_ptr<object1>,boost::shared_ptr<object2> > variant_type; std::vector<variant_type> vec; Only this ensures that no copies of object1/object2 will be made. However, this solution has two problems. The first problem is that shared_ptr can be NULL, and our logic forces the shared_ptr to never be NULL. So I wrote the following class: template <typename T> class shared_ref { public: typedef T value_type; template <typename Y> explicit shared_ref(Y *a_ptr) : m_ptr(a_ptr) { } template <typename Y> explicit shared_ref(std::auto_ptr<Y> a_ptr) : m_ptr(a_ptr) { } T& get() const { T *ptr = m_ptr.get(); assert(ptr); // that's the entire essence of this class return *ptr; } operator T&() const { return get(); } T* operator->() const { return &get(); } private: boost::shared_ptr<T> m_ptr; }; This class is like shared_ptr, but it's never NULL, so I called it shared_ref. The non-null contract is validated in run-time using assert (in the get() function). (BTW, for completeness, I should have added static_cast and dynamic_cast constructors, but I had no immediate use for it, so laziness took control). Thanks to the non-null contract, I could add the implicit conversion operator to T&. The shared_ref solved this first problem, but the second problem is that that shared_ptr/shared_ref use ptr/ref const semantics (a const shared_ref<T> doesn't mean that T is const, only shared_ref<const T> does), and not value const semantics. So I wrote another class: template <typename T> class shared_obj { public: typedef T value_type; explicit shared_obj(T *a_ptr) : m_ref(a_ptr) { } explicit shared_obj(std::auto_ptr<T> a_ptr) : m_ref(a_ptr) { } shared_obj(const shared_ref<T> &a_ref) : m_ref(a_ref) { } T& get() { return m_ref.get(); } const T& get() const { return m_ref.get(); } operator T&() { return get(); } operator const T&() const { return get(); } T* operator->() { return &get(); } const T* operator->() const { return &get(); } private: shared_ref<T> m_ref; }; which gives value const semantics - a const shared_obj<T> means that T is const. Now I can write typedef boost::variant<boost::shared_obj<object1>,boost::shared_obj<object2> > variant_type; The value const semantics, plus the implicit [const] T& converstion operators allow you to use visitors as if it was a regular variant: class my_visitor : public boost::static_visitor<some_type> { some_type operator()([const] object1 &o1) { ... } some_type operator()([const] object2 &o2) { ... } }; Of course, this solution is a workaround to the fact that variant can't handle non-copyable objects. What I would *really* like to see, is variant support for non-copyable classes, something like boost::optional's in-place factory. Unfortunately, the varaint maintainers seem to not follow these lists lately... HTH, Yuval
participants (3)
-
Bjorn.Karlsson@readsoft.com
-
Felipe Magno de Almeida
-
Yuval Ronen