Для чего нужен был вспомогательный класс auto_ptr_ref. Нужны примеры простейшей реализации и использования.
auto_ptr_ref
- пример попытки "красивой" реализации семантики перемещения (move semantics) средствами языка С++98. Стандартный std::auto_ptr
, как известно, должен перемещать право владения памятью при копировании (как конструктором копирования, так и оператором присваивания)
std::auto_ptr<int> pa(new int(42)); // `pa` владеет памятью
std::auto_ptr<int> pb = pa; // теперь `pb` владеет памятью, `pa` пуст
pa = pb; // теперь `pa` владеет памятью, `pb` пуст
Но это создает определенные трудности при реализации всех форм копирования для std::auto_ptr
. Так как копирование модифицирует свою правую часть, параметры конструктора копирования и оператора присваивания по идее должны быть неконстантными ссылками на std::auto_ptr
. Но в этом случае мы не сможем делать что-то вроде
std::auto_ptr<int> foo() { ... }
...
std::auto_ptr<int> p = foo();
т.к. функция foo()
возвращает временный объект, а неконстантные ссылки нельзя привязывать ко временным объектам. Что делать?
Рассмотрим проблему на отвлеченном примере. Предположим, что мы захотели реализовать некий класс S
, хранящий некое целочисленное значение и перемещающий это значение в получателя (в левую часть) при копировании. Правая часть при копировании получает значение -1
struct S
{
int i;
S(int i = -1) : i(i)
{}
S(S &s) : i(s.i)
{ s.i = -1; }
S &operator =(S &s)
{
i = s.i;
s.i = -1;
return *this;
}
};
У нас получилось то, что надо
S a(42);
assert(a.i == 42);
S b = a;
assert(b.i == 42 && a.i == -1);
a = b;
assert(a.i == 42 && b.i == -1);
Однако мы не можем пользоваться нашим классом вот так
S foo() { return S(42); }
...
S a = foo(); // ERROR
S b;
b = foo(); // ERROR
по причине того, что неконстантную ссылку (параметр конструктора и оператора присваивания) невозможно привязать ко временному объекту (к результату foo()
).
В такой ситуации мы можем попробовать "выкрутиться" за счет введения промежуточного класса, который мы назовем Sref
, и который умеет только ссылаться на наш класс S
struct S;
struct Sref
{
S &s;
};
Добавим в наш класс S
оператор конверсии к Sref
, порождающий Sref
-ссылку на самого себя
struct S
{
...
operator Sref()
{
Sref r = { *this };
return r;
}
...
};
А также добавим в наш класс S
конвертирующий конструктор из типа Sref
и аналогичный конвертирующий оператор присваивания, которые ведут себя в соответствии с требуемой нам семантикой, но через ссылку Sref
struct S
{
...
S(Sref sr) : i(sr.s.i)
{ sr.s.i = -1; }
S& operator =(Sref sr)
{
i = sr.s.i;
sr.s.i = -1;
return *this;
}
...
};
и готово - теперь инициализация и присваивание
S a = foo();
S b;
b = foo();
будет прекрасно компилироваться и работать именно так, как мы хотим. Они пойдут по пути
S a(foo().operator Sref());
S b;
b = foo().operator Sref();
Здесь также эксплуатируется то "странноватое" свойство языка, согласно которому хоть к временным объектам и нельзя привязывать неконстантные ссылки, через временные объекты однако можно вызывать их неконстантные методы.
Именно так работает и именно эту роль играет класс auto_ptr_ref
в реализации функциональности std::auto_ptr
.
У auto_ptr конструктор копирования и оператор присваивания принимают ссылку не на константу, поэтому не смогли бы конструироваться из временного объекта.
Код с собственным классом, демонстрирующий проблему:
struct pointer
{
pointer() {}
pointer(pointer &) {}
};
pointer create()
{
return pointer();
}
int main()
{
pointer ptr(create());//Ошибка компиляции
}
Добавим свой pointer_ref для решения проблемы:
struct pointer_ref
{
pointer_ref(const struct pointer&) {}
};
struct pointer
{
pointer() {}
pointer(pointer &) {}
pointer(pointer_ref) {}
};
int main()
{
pointer ptr(create());//Теперь ok
}
Как реализация будет делать auto_ptr_ref - не важно, главное, чтобы он решал проблему.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Пишу очередь с приоритетомНеобходимо перегрузить оператор +, но наталкиваюсь на ошибку: "Вызвано исключение: нарушение доступа для чтения
Совсем запутался с этими кодеками