#c #c 11 #reference
#c #c 11 #ссылка
Вопрос:
В моем приложении у меня есть список объектов. Поскольку у меня должен быть только один экземпляр, я отключил как конструктор копирования, так и оператор присваивания. Перемещение объекта по-прежнему разрешено. Но поскольку я выполняю различные манипуляции с объектами, мне нужно сохранить указатель на один из них. Раньше я использовал указатель для этой цели, но теперь я хочу использовать ссылку.
По какой-то причине я не могу переназначить ссылку. Ошибка:
error: overload resolution selected deleted operator '='
candidate function has been explicitly deleted
Пример кода, демонстрирующий проблему:
#include <iostream>
class Item
{
public:
Item() { n = ( Item::counter); }
Item(const Itemamp;amp; other) { n = std::move(other.n); }
Item(const Itemamp; other) = delete;
Itemamp; operator=(const Itemamp; other) = delete;
int Get() { return n; }
private:
int n;
static int counter;
};
int Item::counter = 0;
int main()
{
Item i1;
Item i2;
Item *p = amp;i1;
printf("%dn", p->Get());
p = amp;i2;
printf("%dn", p->Get());
Item amp;r = i1;
printf("%dn", r.Get());
r = i2; // here I get the error
printf("%dn", r.Get());
return 0;
}
Хорошо, я могу понять, если получу ошибку при чем-то подобном:
Item i3 = i2;
т.е. в случае действительно присваивания. Но здесь я просто хочу сохранить ссылку на объект, а не присваивать или копировать его другому.
Итак, мой вопрос в том, как я могу сохранить ссылку на не скопированный объект, избегая указателей?
Комментарии:
1. «По какой-то причине я не могу переназначить ссылку». Причина в том, что язык этого не допускает.
2. Если вы ожидали повторной привязки этой ссылки к другому объекту, язык работает не так. После привязки при инициализации required ссылка не может быть привязана (но ее можно оставить висящей, если вы не будете осторожны). В вашем коде
r = i2;
является синонимомi1 = i2;
, и вы обнаружите, что это тоже не будет компилироваться.3. Определение оператора конструктора копирования / присваивания явно решает проблему, но это не то, что я хочу. Что касается моего, то это какой-то странный и неожиданный побочный эффект, когда вы отключаете копирование , а затем вы не можете сохранить ссылку на объект, и это определенно не одно и то же.
4. Если вы хотите изменить, на какой объект указывается, вам нужно придерживаться указателей, ссылки могут указывать только на объект, с помощью которого они сначала инициализируются
5. Очевидно, что у вас может быть ссылка. Вы его создали. с
Item amp;r = i1;
помощью But вы не можете повторно привязать эту ссылку к другому объекту, как вы можете с помощью указателя. Язык работает не так. И, кстати, ваша оценкаItem i3 = i2;
как «в случае действительно присваивания» — тоже неточна. Это не присваивание, это инициализация копирования .
Ответ №1:
В C ссылки не могут быть повторно привязаны. Что это значит? Это означает, что после создания ссылки вы не можете изменить объект, на который ссылается эта ссылка. Это имеет серьезные последствия — например, этот код:
Item i1;
Item i2;
Item amp;r = i1;
r = i2;
логически эквивалентно этому:
Item i1;
Item i2;
i1 = i2;
Теперь должно быть понятно, почему у компилятора проблемы с оператором присваивания. Что нужно сделать? Вы можете использовать std::reference_wrapper, который вам нужен — повторно привязываемый ссылочный тип:
Item i1;
Item i2;
auto r = std::ref(i1);
r = std::ref(i2);
Комментарии:
1. Спасибо @bartop, это отличное решение! К сожалению, я ничего об этом не знал.