Boost logo

Boost :

From: David Abrahams (abrahams_at_[hidden])
Date: 2001-01-06 10:38:29


----- Original Message -----
From: "William Kempf" <sirwillard_at_[hidden]>

> The age old problem of smart pointers not working with pointers to
> arrays has resulted in a lot of different solutions. A recent
> posting to comp.lang.c++ sounds interesting and I thought some folks
> on here might like to comment and maybe consider this technique for
> some of the Boost smart pointers.

In principle, this is an ingenious idea

> Here is an example specialization of auto_ptr on X[]. Note that it
> is not portable because it depends upon implementation details of
> auto_ptr_ref.

My red flag just went up...

> Nevertheless, I believe that the idea should easily
> port to any
> environment with an existing std::auto_ptr and which supports partial
> specialization:
>
> namespace std
> {
>
> template<class X>
> class auto_ptr<X[]>
> {
> public:
> typedef X element_type;
>
> // lib.auto.ptr.cons construct/copy/destroy:
> explicit auto_ptr(X* p = 0) throw() : ptr_(p) {}
> auto_ptr(auto_ptr& a) throw() : ptr_(a.release()) {}
> auto_ptr& operator=(auto_ptr& a) throw()
> {reset(a.release()); return *this;}
> ~auto_ptr() throw() {delete [] ptr_;}
>
> // lib.auto.ptr.members members:
> X& operator*() const throw() {return *ptr_;}
> X* operator->() const throw() {return ptr_;}
> X* get() const throw() {return ptr_;}
> X* release() throw()
> {X* tmp = ptr_; ptr_ = 0; return tmp;}
> void reset(X* p = 0) throw()
> {if (ptr_ != p) {delete [] ptr_; ptr_ = p;}}
> X& operator[](size_t n) {return *(get() + n);}
> const X& operator[](size_t n) const {return *(get() + n);}
>
> // lib.auto.ptr.conv conversions:
> auto_ptr(auto_ptr_ref<X> r) throw() : ptr_(r.ptr_) {}
> auto_ptr& operator=(auto_ptr_ref<X> r) throw()
> {reset(r.ptr_); return *this;}
> operator auto_ptr_ref<X>() throw()
> {auto_ptr_ref<X> r; r.ptr_ = release(); return r;}

I think this is a mistake. Conversions to/from auto_ptr_ref<X> allow us to
convert between auto_ptr<X> to auto_ptr<X[]>, which will call the wrong
version of delete. I think you need to use a new class, e.g.
auto_ptr_array_ref, to do this. And since you aren't depending on details of
auto_ptr_ref any more, it should work portably.

> private:
> X* ptr_;
> };
>
> }
>
> Now the example code does compile and has the expected semantics:
>
> auto_ptr<char []> ptr(new char[100]);
>
> Notes:
>
> 1. Conversions from derived to base pointers are not supported in
> this specialization since that would result in undefined behavior
> (5.3.5/3).
>
> 2. The specialization sports operator[] as a convenience.
> ptr[0] = ...;
> ptr[1] = ...;
> ...
> But attempts to use operator[] with non-array types (the original
> auto_ptr) will compile-time.
>
> I'm thinking along the lines of this being part of the next C++
> standard. But it needs lots more field testing and thought than I can
> give it alone.
>
> This could have code size and/or speed advantages over the usual
> suggestion to "use vector instead".
>
> Thoughts? Comments? Opinions?

I think it's a great approach. I only hope that the deep hatred engendered
by auto_ptr in some quarters doesn't doom it to obscurity.

-Dave


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk