Подтвердить что ты не робот

С++ возвращает ссылку из функции с типом разыменованного типа?

В следующей функции я хочу взять вектор objects и вернуть копию одного из элементов этого вектора. Поскольку приведенный ниже код компилируется правильно, я предполагаю, что итератор copy_objects.back() автоматически разыменован. Но я точно не знаю. Что происходит в заявлении return?

MyObject best(vector<MyObject>& objects) {
    vector<MyObject> copy_objects = objects;
    sort(copy_objects.begin(), copy_objects.end(), compare_MyObject_func);
    return copy_objects.back();
}

Я знаю, что есть другие способы выполнить простую задачу, но мне любопытно узнать, что происходит в этом примере.


Последующий вопрос...

Используя определение выше описанной функции best, я получаю следующую ошибку компиляции:

error: invalid initialization of non-const reference of type ‘std::vector<MyObject>&’ from an rvalue of type ‘std::vector<MyObject>’
     bestObject = best(myfunction(objects));
                                          ^

Если объявления соответствующего типа:

MyObject bestObject;
vector<MyObject> objects;
vector<MyObject> myfunction(vector<MyObject>&);

Моя интуиция подсказывает мне, что эта ошибка связана с исходным вопросом выше. Но я не понимаю, в чем проблема.

4b9b3361

Ответ 1

"Разница" обычно относится к применению унарного оператора * указателю или другому итератору (например, *p). Эта терминология сбивает с толку, потому что она не имеет ничего общего со ссылочными типами на С++, поэтому комитет по стандартизации переходит к использованию "выполнить косвенную".

В любом случае copy_objects.back() не возвращает итератор вообще. Он возвращает ссылку на объект (фактический ссылочный тип). Это можно увидеть, потому что тип возврата для std::vector<T>::back равен const_reference, который является typedef для const value_type&, где value_type - T. Вы никогда не "разыгрываете" ссылки. Если вы хотите скопировать ссылку, вам просто нужно обработать ее как обычный объект.

int x = 0;
int& y = x;
int z = y;

В этом примере z будет копией объекта, на который ссылаются как x, так и y.


В дополнение к этому, я рекомендую просто принимать аргумент по значению (удалить &):

MyObject best(vector<MyObject> objects) {
  sort(objects.begin(), objects.end(), compare_MyObject_func);
  return objects.back();
}

Вы все равно его скопируете, поэтому брать его по ссылке бессмысленно. В частности, ссылка не const предполагает, что вы собираетесь изменить данный аргумент, которого нет. Фактически, ссылочный параметр дает худшую производительность, когда vector может быть перемещен в функцию. Параметр ссылочного типа никогда не будет перемещаться.


Отвечайте на расширенный вопрос:

myfunction возвращает значение, что означает, что возвращаемый объект является временным объектом (это копия того, что внутри него). Вы не можете привязать ссылку не const (параметр best) к временному объекту. Это имеет смысл, потому что тогда временный объект исчезнет (потому что он временный), и ссылка останется без ничего.

Если вы указали тип параметра a const, это было бы хорошо, потому что ссылки const продлевают срок службы временного объекта. Если вы сделали параметр не ссылкой, это также было бы хорошо, потому что это сделало бы локальную копию временного объекта.

Ответ 2

back() не возвращает итератор. Вместо этого он возвращает ссылку на последний элемент вектора.

Ответ 3

Вы выполняете мелкую копию объектов, а затем сортируете копию. back() возвращает ссылку на последний элемент, поэтому вы делаете копию из этой ссылки в возвращаемую переменную в области вызова.

Ответ 4

Вы передаете ссылку - следовательно, вы можете вернуть ссылку:

MyObject& best(vector<MyObject>& objects) {
    vector<MyObject>::iterator result = objects.begin();
    if(result == objects.end()) throw std::runtime_error("Empty");
    else {
        for(vector<MyObject>::iterator pos = std::next(result);
            pos != objects.end();
            ++pos)
        {
            // Might be ! compare_MyObject_func 
            if(compare_MyObject_func(*result, *pos)) result = pos;
        }
    }
    return *result;
}

Не нужно ничего сортировать, если вы заинтересованы только в определенном элементе.

Примечание: сложность поиска определенного элемента равна O (n), а сортировка - O (n log (n))