Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2001-01-04 14:35:46


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.

Original message from Howard Hinnant:

In article <ErM46.13826$534.6573_at_[hidden]>, "Luca"
<luca_at_[hidden]> wrote:
 
| Can auto_ptr handle raw arrays properly?
| auto_ptr<char []> ptr(new char[100]);
|
| Will the array be properly deleted when ptr goes out of scope?
 
Interesting syntax suggestion.
 
As others have stated, no this won't work. But I wanted to explore
your syntax suggestion a little...
 
auto_ptr<char []> ptr(new char[100]);
 
On my system this results in a compile-time error:
 
Error : function call 'auto_ptr(char *)' does not match
'std::auto_ptr<char[]>::auto_ptr(char (*)[])'
'std::auto_ptr<char[]>::auto_ptr(std::auto_ptr<char[]>
&)' 'std::auto_ptr<char[]>::auto_ptr<...>(std::auto_ptr<T1_0>
&)' 'std::auto_ptr<char[]>::auto_ptr(std::auto_ptr_ref<char[]>)'
HelloWorld2.cpp line 39 std::auto_ptr<char []> ptr(new char[100]);
 
This means to me that we could (non-portably for the moment)
specialize auto_ptr on X[] and give it the desired semantics without
worrying about changing the behavior of existing working code.
 
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. 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;}
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?
 
-Howard


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