Перемещение семантики и возврат константных значений

У меня есть привычка (?!?!?) возвращать все как "константное" значение. Так...

struct s;

s const make_s();

s const &s0 = make_s();
s const s1 = make_s();

С операциями перемещения и ссылками на r-значение и следующими функциями...

void take_s(s &&s0);
void take_s(s const &&s0);  //  Doesn't make sense

Я больше не могу писать...

take_s(make_s());

Основная причина, по которой я начал использовать соглашение о возврате константных значений, заключается в том, чтобы не дать кому-то написать такой код...

make_s().mutating_member_function();

Вариант использования следующий...

struct c_str_proxy {
    std::string m_s;

    c_str_proxy(std::string &&s) : m_s(std::move(s)) {
    }
};

c_str_proxy c_str(std::string &&s) {
    return c_str_proxy(s);
}

char const * const c_str(std::string const &s) {
    return s.c_str();
}

std::vector < std::string > const &v = make_v();
std::puts(c_str(boost::join(v, ", ")));

std::string const my_join(std::vector < std::string > const &v, char const *sep);

//  THE FOLLOWING WORKS, BUT I THINK THAT IS ACCIDENTAL
//  IT CALLS
//
//      c_str(std::string const &);
//
//  BUT I THINK THE TEMPORARY RETURNED BY
//
//      my_join(v, "; ")
//
//  IS NO LONGER ALIVE BY THE TIME WE ARE INSIDE
//
//      std::puts
//
//  AS WE ARE TAKING THE "c_str()" OF A TEMPORARY "std::string"
//
std::puts(c_str(my_join(v, "; ")));

Похоже, что «возвращаемое константное значение» и ссылки на r-значение не смешиваются в этом конкретном случае использования. Это правильно?

**Edit 0: Extra question...**

В любом случае объект временный. Почему "const" должен препятствовать движению? Почему мы не можем перемещать "константные" временные файлы?


person zrb    schedule 21.08.2011    source источник
comment
Я действительно не вижу смысла возвращать константные значения. Зачем вам заботиться о том, чтобы люди не вызывали изменяющую функцию-член для возвращаемого объекта?   -  person jalf    schedule 21.08.2011
comment
Пример идиомы возврата константного значения можно найти в Meyers, More Effective c++, 1996, Item 6. Мейерс рекомендует const T operator++(int) в качестве подписи для postfix++.   -  person Adam Burry    schedule 13.09.2013


Ответы (3)


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

Вам нужно принять решение. Вы хотите, чтобы объект был неизменным, или вы хотите, чтобы люди могли его изменять?

Что бы это ни стоило, я действительно не понимаю, что вы получите, возвращая временные константы в первую очередь. Да, вы запрещаете людям вызывать для него изменяющую функцию-член, но зачем вам это нужно? В лучшем случае это может быть полезно, а в худшем — это ошибка, которой легко избежать.

И то, что ты делаешь, не имеет особого смысла. Вся суть временного в том, что через мгновение оно исчезнет, ​​так что кого волнует, изменится ли оно?

Вся идея, лежащая в основе ссылок rvalue и семантики перемещения, заключается в том, что временные объекты являются временными, и поэтому их можно изменять, не причиняя никому вреда.

person jalf    schedule 21.08.2011
comment
да. Единственный случай, когда вы хотели бы вернуть что-то константное, — это когда это ссылка или указатель на объект, который вы не хотите, чтобы вызывающая сторона могла изменить. В противном случае, пусть они меняются прочь. - person AFoglia; 23.09.2011
comment
На самом деле, возврат const rvalue полезен для предотвращения таких ошибок, как: if (a * b = c) if тип a*b может быть назначен с помощью c и может быть неявно преобразован в bool... ну. Это крайний случай, но его легко избежать, возвращая пользовательские типы как константы. При тестировании на компиляторе vc14 я вижу, что const rvalue, возвращаемое функцией, по-прежнему отправляется в конструктор перемещения. Есть ли что-то новое в С++ 14, которое указывает на это, или это только оптимизация, специфичная для компилятора? - person ; 10.03.2017

У вас могут возникнуть проблемы с выходом локальной переменной за пределы области видимости.

c_str() возвращает указатель на внутренний буфер, поэтому, как только исходная переменная выйдет за пределы области видимости, указатель станет недействительным.

person Šimon Tóth    schedule 21.08.2011
comment
Я знаю об этом, но вопрос действительно о возврате константных значений. Я предполагаю, что даже со ссылками на r-значение возврат константных значений предотвращает перемещение. То, что я раньше считал хорошей практикой, вдруг оказывается неверным. - person zrb; 21.08.2011

Квалификатор const в возвращаемом значении не имеет семантического значения. Если вы включите уровень предупреждения на своем компиляторе, он будет выдавать предупреждение каждый раз, когда вы это делаете.

person user566408    schedule 21.08.2011
comment
Это абсолютно неверно как общее утверждение. Может быть, вы можете уточнить или дать ссылку на то, о чем конкретно вы говорите? - person wjl; 09.11.2011