Mail.ruПочтаМой МирОдноклассникиВКонтактеИгрыЗнакомстваНовостиКалендарьОблакоЗаметкиВсе проекты

Не могу разобраться с константными ссылками

Felix Noskov Гуру (2614), закрыт 1 год назад
Когда стал разбираться с Lvalue- и Rvalue-ссылка, встретил такой код:

string get_str() {
string s = "hello";
return s;
}

int main () {
...
string const& a = get_str (); // (1)
string& b = get_str (); // Ошибка! (2)
...
}

И не понял, почему вызов функции работает в случае (1).
В случае (2) понятно, что мы пытаемся сделать ссылку b на содержимое переменной s, которое сразу же очищается после завершения функции, поэтому мы делаем ссылку на несуществующую область памяти, отсюда и ошибка.
Но как эту проблему решает константная ссылка?
Вычитал, что "константная ссылка продлевает время жизни", но я не могу понять как и какой у этого механизм в данном случае?
Лучший ответ
Slava Ivanov Мудрец (14446) 1 год назад
Модификатор const и решает проблему - сохраняет адрес и хранящееся на нём значение. Но это очень рискованный код, не надо так делать. Результат будет сильно зависеть от компилятора. И лучше всегда использовать указатели, не гонитесь за красотой кода, передавать по указателю изменяемый параметр в функцию не сложнее, чем по ссылке. Причину ошибки вы нашли правильно, но и пример 1 выглядит сомнительно.
Felix NoskovГуру (2614) 1 год назад
Правильно ли понял, что приравнивание "s" к константной "a", просто "защищает" область от очищения при раскрутке стека функции?
Согласен, что в этом примере ссылки выглядят, как минимум странно, как максимум "а зачем отрывать её от адреса в памяти", но я решил сохранить синтаксис примера для вопроса
Slava Ivanov Мудрец (14446) Felix Noskov, в общем да - но это явно делает не язык, а компилятор с защитой от таких вещей, и если вы хотите знать точно - декомпилируете этот код. Assembler знает всё! Увидите что и как происходит с адресацией и что на что и когда ссылается.
Остальные ответы
Николай Веселуха Высший разум (385103) 1 год назад
 #include  
#include

using namespace std;

const auto get_str() {
string s = "hello";
return move(s);
}

int main ()
{
auto a = get_str();
cout << a << '\n';

auto& b = get_str();
cout << b << '\n';

const auto c = get_str();
cout << c << '\n';

const auto& d = get_str();
cout << d << '\n';

string e = get_str();
cout << e << '\n';

const string f = get_str();
cout << f << '\n';

const string& g = get_str();
cout << g << '\n';

string& h = a;
cout << h << '\n';

string& i = e;
cout << i << '\n';
}
 string& s = string("hello"); // недопустимая инициализация
const string& cs = string("hello"); // допустимая инициализация
const string& cch = "hello"; // допустимая инициализация
В первом случае ссылка не константная, а следовательно по ней допускается изменять значение, но переменной как таковой нет, что приведёт к ошибке компиляции. По сути это анонимный адрес на строковый литерал. А инициализировать константные ссылки можно, потому как анонимный объект не предполагается изменять. Это позволяет при передаче параметров в функции и методы избежать затрат на копирование, а также создавать временные объекты.

Ну и правила:
  1. lvalue, могут быть преобразованы в rvalue, если они не являются массивом, функцией и не имеют неполный тип.
  2. rvalue в lvalue преобразовать не допускается, то есть везде где ожидается lvalue можно присвоить только lvalue
Похожие вопросы