#include <memory>

/* 
 * Auto-deleting arrays.
 *
 * This is a work-alike to std::auto_ptr.  Wrapping auto_ptr in some
 * kind of array_deleter<> object to convert delete into delete[] has
 * the overhead of allocating an extra pointer-sized object for every
 * use, which is silly, avoidable overhead even if it is more elegant.
 *
 * See also http://www.gotw.ca/gotw/042.htm
 */

template <typename T>
class auto_array;

template <typename T>
class auto_array_ref
{
public:  auto_array_ref(T* t) : array(t) { }
private: T* array;
friend class auto_array<T>;
};

template <typename T>
class auto_array
{
public:
	typedef T element_type;

	auto_array(T *a) : array(a) {}
	~auto_array() { delete[] array;  }
	
	template<typename T2>
	auto_array(auto_array<T2> &aa) : array(aa.release()) {}

	template<typename T2>
	auto_array& operator= (auto_array<T2> &aa)
	{
		if (array) delete[] array;
		array = aa.release();
		return *this;
	}

	T* release() { T* tmp = array; array = 0; return tmp; }

	T* get()              const { return array;    }
	T& operator[](int i)  const { return array[i]; }


	auto_array(auto_array_ref<T> r) : array(r.array) {}

	template<typename T2>
	auto_array& operator= (auto_array_ref<T2> r)
	{
		if (r.array != array) {
			delete[] array;
			array = r.array;
		}
		return *this;
	}

	template <typename T2>
	operator auto_array_ref<T2>() { return auto_array_ref<T2>(release()); }

	template <typename T2>
	operator auto_array<T2>() { return auto_array<T2>(release()); }

private:
	T *array;
};




#include <iostream>

class Noisy
{
public:
	Noisy()  { std::cout << "Constructed" << std::endl; }
	~Noisy() { std::cout << "Destructed"  << std::endl; }
};

int main()
{
	std::cout << "With auto_ptr:" << std::endl;
	{
		std::auto_ptr<Noisy> n(new Noisy[2]);
		// might crash here
	}
	std::cout << "With auto_array:" << std::endl;
	{
		auto_array<Noisy> n(new Noisy[2]);
	}
}

/* Typical output:

With auto_ptr:
Constructed
Constructed
Destructed
<may crash here, depending upon your C++ runtime implementation>
With auto_array:
Constructed
Constructed
Destructed
Destructed

*/

