Передать временный объект функции, которая принимает указатель

Я пробовал следующий код:

#include<iostream> 
#include<string>
using namespace std;

string f1(string s)
{
   return s="f1 called";
}

void f2(string *s)
{
   cout<<*s<<endl;
}

int main()
{
   string str;
   f2(&f1(str));
}

Но этот код не компилируется.
Что я думаю: f1 возвращается по значению, поэтому он создает временные, из которых я беру адрес и передаю на f2.
Теперь, пожалуйста, объясните мне, где я ошибаюсь?


person Happy Mittal    schedule 06.06.2010    source источник


Ответы (4)


Унарный & принимает lvalue (или имя функции). Функция f1() не возвращает lvalue, она возвращает rvalue (для функции, которая что-то возвращает, если она не возвращает ссылку, ее возвращаемое значение - rvalue), поэтому к ней нельзя применить унарный &.

person James McNellis    schedule 06.06.2010
comment
Но я могу использовать f1 () следующим образом: f1 (str) = happy; Здесь я использую временное значение в качестве l-значения. - person Happy Mittal; 06.06.2010
comment
Счастливого Миттала, слово lvalue может немного сбивать с толку - оно больше не означает значение, которое может стоять слева от задания. когда вы используете оператор =, вы фактически вызываете функцию-член строкового объекта. Вам разрешено использовать члены rvalues. - person avakar; 06.06.2010
comment
Итак, что бы произошло, если бы в строке был явный оператор & {return this;}? - person user168715; 06.06.2010
comment
@user: временное значение, возвращаемое f1(), существует до конца полного выражения, в котором оно создано; это означает, что его время жизни эффективно с момента, когда f1() вернет его, до момента, когда f2() вернет. Итак, я бы подумал, что перегруженный унарный & позволит вам получить указатель на временный объект (хотя думать об этом несколько пугающе и ужасно). - person James McNellis; 07.06.2010

Можно создать (и передать) указатель на временный объект, если вы знаете, что делаете. Однако делать это нужно иначе.

Функция с возвращаемым значением не ссылочного типа возвращает rvalue. В C ++ применение встроенного унарного оператора & к rvalue запрещено. Требуется lvalue.

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

const string &r = f1(str);
f2(&r);

которые также можно сложить в одну линию с помощью гипса

f2(&(const string &) f1(str));

В обоих случаях, описанных выше, функция f2 должна принимать параметр const string *. Просто string *, как в вашем случае, не будет работать, если вы не откажетесь от константности из аргумента (что, кстати, сделает все это еще более уродливым, чем оно есть). Хотя, если мне не изменяет память, в обоих случаях нет гарантии, что ссылка будет прикреплена к временному оригиналу, а не к копии.

Просто имейте в виду, что создание указателей на временные объекты - довольно сомнительная практика, потому что очевидные проблемы с временем жизни. Обычно вам следует избегать этого.

person AnT    schedule 06.06.2010

Ваша программа не компилируется, потому что f1 имеет параметр, а вы его не передаете.

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

person avakar    schedule 06.06.2010
comment
О ... Моя плохая. Но он по-прежнему предупреждает: взяв адрес временного - person Happy Mittal; 06.06.2010
comment
Счастливый Миттал, да, потому что это rvalue. Представьте, что функция возвращает int вместо string, это может быть более очевидным - возвращаемое значение не обязательно должно иметь соответствующую ячейку памяти. - person avakar; 06.06.2010

Попробуй это:

int main()
{
    string str;
    string str2 = f1(str); // copy the temporary
    f2(&str2);
}
person egrunin    schedule 06.06.2010
comment
Это одна ненужная копия. (Если вы не возражаете против ненужного копирования строк, зачем вообще беспокоиться о C ++?) Если вы привяжете rvalue к const ссылке, время жизни rvalue будет продлено до конца времени жизни ссылки. Итак, const std::string& str2=f1(str); - это то, что вы хотите. - person sbi; 07.06.2010
comment
@sbi: Мой пример, как и его, намного проще любого реального кода. - person egrunin; 07.06.2010
comment
Обратите внимание: ваши ответы - научить людей делать то, чего они еще не знают. Даже если вы упускаете что-то только потому, что это не имеет отношения к вашему аргументу, другие все равно могут перенять от этого неправильную привычку. - person sbi; 07.06.2010
comment
@sbi Copy elision, вероятно, делает два предложенных фрагмента кода одинаковыми, а этот выглядит менее непонятным. Ваш ответ более прямо отвечает на вопрос, но я не уверен, что был задан правильный вопрос. ;) - person underscore_d; 02.07.2017
comment
@underscore_d: Если вы думаете, что const ссылки неясны, вам нужно наверстать упущенное. :) - person sbi; 05.07.2017
comment
@sbi Obscure, конечно, было неправильным словом. Я имел в виду немного более запутанный. : P Но сейчас я программирую на C, поэтому любой C ++ мне кажется более понятным ... - person underscore_d; 05.07.2017