auto_ptr
использует подвох.
Я буду использовать скрытый класс с именем auto_int
, чтобы продемонстрировать только функциональность создания копии, не внося никаких сложностей, связанных с шаблонами или наследованием. Я думаю, что код в основном правильный, но он не проверен. Наши базовые auto_int
выглядят примерно так:
class auto_int
{
public:
auto_int(int* p = 0) : p_(p) { }
~auto_int() { delete p_; }
// copy constructor taking a non-const reference:
auto_int(auto_int& other)
: p_(other.release()) { }
int* release()
{
int* temp = p_;
p_ = 0;
return temp;
}
private:
int* p_;
};
С помощью этого базового auto_int
мы не можем скопировать временный объект. Наша цель - написать что-то вроде:
auto_int p(auto_int(new int()));
Что мы можем сделать, это использовать вспомогательный класс. Для auto_ptr
это называется auto_ptr_ref
. Мы позвоним нашим auto_int_ref
:
class auto_int;
class auto_int_ref
{
public:
auto_int_ref(auto_int* p) : p_(p) { }
auto_int& ref() { return *p_; }
private:
auto_int* p_;
};
По сути, экземпляр этого класса просто хранит указатель на auto_int
и позволяет нам использовать его как «ссылку» на auto_int
.
Тогда в нашем auto_int
классе нам понадобятся две дополнительные функции. Нам нужен другой конструктор, который принимает auto_int_ref
, и нам нужен оператор преобразования, который позволяет неявно преобразовывать auto_int
в auto_int_ref
:
auto_int(auto_int_ref other)
: p_(other.ref().release()) { }
operator auto_int_ref() { return this; }
Это позволит нам «копировать» временный файл, в то время как конструктор копирования принимает неконстантную ссылку. Если мы снова посмотрим на наш пример кода:
auto_int p(auto_int(new int()));
Что происходит, мы создаем новый временный auto_int
и передаем new int()
в конструктор, который принимает int*
. Затем это временное значение преобразуется в auto_int_ref
, который указывает на него, с использованием operator auto_int_ref()
, а конструктор auto_int
, который принимает auto_int_ref
, используется для инициализации p
.