Тернарный оператор дает неожиданные результаты в операторе возврата - PullRequest
0 голосов
/ 01 октября 2018

Я получаю очень странные результаты от троичного оператора, который должен возвращать ссылку на объект члена связанного списка.У меня есть функция-член в моем объекте базы данных, например:

Month& GetLastMonth() { return months_.Size() > 0 ? months_.Last() : Month(); }

Я вызываю эту функцию 2 раза в коде: сразу после загрузки БД для получения информации, а также при изменении некоторых параметров месяца и нажатии кнопки.

Первый раз, когда я пишу это для справки, ничего страшного в этом нет.Но во второй раз мне нужна неконстантная ссылка на пересчет месяца (поэтому он изменится и в БД).

Но вместо ожидаемых результатов случается какая-то черная магия.Каждый раз, когда я вызываю функцию GetLastMonth(), она возвращает ссылку с другим адресом.Итак, после загрузки БД - ее 1 адрес, пересчет месяца - ее 2-й адрес и сразу после сохранения в файл 3-й адрес.Конечно, из-за этого мои изменения после пересчета месяца не сохраняются в файл.

Теперь размер months_ всегда равен 1 (для целей тестирования).Также это связанный список, поэтому Месяц никогда не сможет перераспределить.Я проверил его, и он никогда не вызывает Month(), поэтому кажется, что троичный оператор работает нормально.

Вызов этого так дает тот же результат:

Month& GetLastMonth() { return months_.Size() ? months_.Last() : Month(); }

Hoverver, если явызовите его без троицы:

Month& GetLastMonth() { return months_.Last(); }

Или с правильным if():

Month& GetLastMonth()
{ 
    if(months_.Size() > 0)
    {
        return months_.Last();
    }
    return Month();
}

Работает, как ожидалось, и возвращает ссылку с одним и тем же адресом все 3 раза.Я думал об этой неясной вещи около 2 дней, но до сих пор не могу найти никакого объяснения этому.

Редактировать: Смежный вопрос: Тип возврата '?:' (Троичный условный оператор)

1 Ответ

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

Тернарный оператор находит общий тип значений и для обоих операндов, и этого не происходит в двух других случаях, поэтому он работает там.

months_.Last() и Month() оба имеют тип Month, так что все в порядке.Но теперь давайте рассмотрим категории значений.months_.Last() - это lvalue, а Month() - это prvalue!Таким образом, общая категория значений здесь является prvalue, и оба операнда преобразуются в prvalue.Это означает, что вы получаете новый Month от months_.Last() каждый раз (из копии)!

Обратите внимание, однако, что это расширение для MS.Без этого расширения код был бы недействительным, поскольку вы пытались бы связать значение prvalue, возвращаемое условным оператором, с неконстантной ссылкой lvalue.

...