Почему мой объект все еще копируется, когда я пытался вернуть ссылку - PullRequest
0 голосов
/ 15 октября 2018
class Obj {
public:
    Obj(int aa, int bb): a(aa), b(bb) {}
    Obj(const Obj& o) {a = o.a; b = o.b;std::cout << "copying" << std::endl;}
    Obj(Obj&& o) {a = o.a; b = o.b;std::cout << "moving" << std::endl;}
    int a;
    int b;
};
const Obj& Min(const Obj &o1, const Obj &o2) {
    if (o1.a > o2.a) {
        return o1;
    } else {
        return o2;
    }
}
int main() {
    using namespace std;

    auto o1 = Obj(1,1);
    auto o2 = Obj(2,2);
    auto res = Min(o1, o2);

    cout << res.a << endl;
    res.a = 100;
    cout << o1.a << endl;
    cout << o2.a << endl;

    return 0;
}

Программа все еще печатает слово copying, которое указывает, что конструктор копирования активирован.Где тогда вызывается конструктор?Почему функция не возвращает ссылку o1, поэтому изменение значения res также изменит значение o1?

Ответы [ 2 ]

0 голосов
/ 15 октября 2018

Это связано с тем, как auto выводит тип:

Из рабочего проекта CPP (N4713):

10.1.7.4.1 Тип заполнителядедукция [dcl.type.auto.deduct]
...
4. Если заполнитель является автоматическим спецификатором типа, выводимый тип T ', заменяющий T, определяется с использованием правил вывода аргументов шаблона.,

И:

17.9.2.1 Вывод аргументов шаблона из вызова функции [temp.deduct.call]
...
2. Если P не является ссылочным типом:
...
(2.3) - Если A является cv-квалифицированным типом, cv-квалификаторы верхнего уровня типа A игнорируются для вывода типа.

Если P является ссылочным типом, для вывода типа используется тип, на который ссылается P.

Так что auto в приведенном ниже выражении

auto res = Min(o1, o2);

выводит res как Obj, вызывая таким образом конструктор копирования при назначении.

Таким образом, изменив вышеприведенное значение следующим образом:

auto& res = Min(o1, o2);

позволит auto выводить resкак const Obj&.

Но если вы сделаете это, res не может быть изменено в основном, так как это const ссылка

0 голосов
/ 15 октября 2018

Копирование выполняется в выписке:

auto res = Min(o1, o2);

Min() тип возврата const Obj&.auto выше будет выведено на Obj, а не const Obj& (т. Е. Тип res будет Obj).res, который является объектом, инициализируется с помощью конструктора копирования (т. Е. Obj::Obj(const Obj&)), поэтому создается конструкция копирования.

Если вы пишете вместо этого:

auto& res = Min(o1, o2)

res будет иметь тип const Obj&, и там не будет создаваться копия, поскольку res будет ссылкой, а не объектом.

...