2016-10-09 5 views
0

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

int *myFunc() { 
    int phantom = 4; 
    return &phantom; 
} 

Тогда обычный аргумент в том, что, когда функция используется, память переменной phantom больше недоступна после выполнения строки кода int phantom = 4; поэтому он не может быть возвращен (по крайней мере, это то, что у меня есть до сих пор понятых). С другой стороны, для функции,

int myFunc() { 
    int phantom = 4; 
    return phantom; 
} 

значение целого числа переменной phantom вернется. (Я вижу возвращение значения как разыменование основного указателя для переменной phantom).

Что мне здесь не хватает ?? Почему в первом случае возникает ошибка компиляции, а во втором случае все работает?

ответ

2

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

Второй код копирует значение. Локальная переменная внутри функции никогда не понадобится ссылаться или использоваться после завершения инструкции return.

+0

Указатель является ссылкой. Это просто не ссылка на C++. – xaxxon

+3

@xaxxon Важное значение имеет правильная терминология :) –

+0

@xaxxon: Технически ссылка похожа на указатель константы, не содержащий NULL. Но они имеют разную семантику и не должны быть объединены. Я бы сказал, что у Йоахима Пилеборга есть правильный ответ, но также стоит упомянуть, что в большинстве простых случаев, таких как NRVO, он ударит и удалит копию. Поэтому стоит просто вернуться к стоимости, пока вам не понадобится вернуть BigHonkingObject, который должен быть выделен в виде кучи. – djrollins

0

Вы не очень скучаете. Только в первом случае ошибки компилятора не будет.

[...] память переменной фантома больше не доступна после выполнения строки кода int phantom = 4; поэтому он не может быть возвращен

Нет, его можно вернуть, и компиляторы могут выдавать предупреждение за это, но afaik не несет никакой ошибки. Однако вы не должны!

Btw, память доступна, но это неопределенное поведение для доступа к ней после возврата функции (не после строки int phantom = 4;).

Во втором случае:

я вижу возвращение стоимости как разыменования нижележащего указателя для переменного фантома

Вы думаете слишком сложно здесь. Возвращение значения из функции может быть реализовано с помощью указателя, но это детализация реализации. Единственное, что вам нужно заботиться, это то, что возвращается значение. Поэтому во втором случае проблем нет.

+0

Фактический вопрос заключается в следующем: если память локального переменного фантома исчезает, то как значение фантома возвращается во втором случае? Как-то это значение должно храниться где-то, чтобы быть возвращенным в конце функции ... Правильно? –

+0

@ noob-математическая память не исчезает. Во втором случае копия значения возвращается вызывающему. Этот механизм не имеет ничего общего с некоторой переменной, которую вы могли бы объявить внутри функции.У вас также может быть 'return 1;' – user463035818

+0

@ noob-математик, который вы, возможно, захотите прочитать о [оптимизации возвращаемого значения] (https://en.wikipedia.org/wiki/Return_value_optimization). Может быть, это помогает немного прояснить ситуацию. – user463035818

-1

Попробуйте вернуть указатель и разыграть его, чтобы получить значение.

#include <iostream> 

using namespace std; 


int *myFunc() 
{ 

    int number = 4; 
    int *phantom = &number; 

    return phantom; 

} 

int main() 
{ 
    cout << myFunc() << endl; //0x.... 
    cout << *myFunc() << endl; //4 
    return 0; 
} 
0

Первый случай

int* myFunc() 
{ 
    int phantom = 4; 
    return &phantom; // you are returning the address of phantom 
}     // but phantom will not "exist" outside of myfunc 

не работает, поскольку переменная phantom является локальной переменной и он живет только во время исполнения myfunc. После этого он исчез.

Вы возвращаете адрес переменной, который будет практически «не существовать».

Правило: никогда не возвращать указатели или ссылки на локальные переменные.

Это нормально:

int myFunc() 
{ 
    int phantom = 4; 
    return phantom; // you are returning by value; 
        // it doesn't matter where phantom "lives" 
}     

int main() 
{ 
    int x = myFunc(); // the value returned by myFunc will be copied to x 
} 
+0

Большинство людей, которые говорят, что второе - Ок, не имеют понятия, почему это Ок. И это вопрос моего вопроса. Если первая не в порядке, почему вторая - это ОК? Чтобы вернуть целое число во втором сценарии, вам нужно «хранить» его где-то, иначе, следуя логике первого сценария, локальная переменная исчезает прямо перед оператором return. –

+1

@ noob-mathematician: C++ гарантирует, что он будет работать; период. Не имеет значения, какой механизм использует ваш конкретный компилятор для выделения/сохранения/сохранения этого значения. Вам нужно только знать, что это так. –

+0

@ noob-mathematician: * «Большинство людей, которые говорят, что второе - Ок, понятия не имею, почему это нормально». * - Это довольно растянуто! :) –

0

Я не совсем уверен, что я понял, почему существует проблема, когда мы возвращаем ссылку локальной случайной величины

Поскольку стандарт C++ говорит, что это неопределенное поведение, если вы используете такую ​​функцию и хотите избежать неопределенного поведения в вашей программе. То, что делает ваша программа, должно определяться правилами языка C++, а не быть случайным.

Обратите внимание, что вы возвращаете указатель, а не ссылку. Но в обоих случаях это неопределенное поведение.

Тогда обычный аргумент в том, что, когда функция используется, память переменной phantom больше недоступна после выполнения код строки int phantom = 4; поэтому он не может быть возвращен (по крайней мере, это является то, что Я понял до сих пор).

Это реализация ориентированной точка зрения и может помощи вам в понимании проблемы.

Тем не менее, важно различать наблюдаемое поведение программы и внутренние трюки компилятора для создания такого поведения. Вы даже не знаете, занята ли какая-либо память переменной в любом случае. Учитывая правило «как-если» и оптимизацию компилятора, вся функция, возможно, была удалена, даже если было определено поведение. Это всего лишь один пример того, что действительно может произойти за кулисами.

Но, в любом случае, это неопределенное поведение, так что все может случиться.

Вопрос в том, почему стандарт C++ не определяет поведение для случая, когда вы возвращаете такой указатель, а затем пытаетесь получить доступ к указателю? Ответом на это было бы то, что это не имеет смысла. Объект, названный локальной переменной phantom, заканчивает свою жизнь, когда функция возвращается. Таким образом, у вас будет указатель на то, что больше не существует, но оно все еще является int*, и разыменование не nullptrint* должно давать int. Это противоречие, а стандарт C++ просто не утруждает себя решением такой бессмысленной ситуации.

Обратите внимание, что это наблюдение основано на правилах языка C++, не на проблемы реализации компилятора.

Почему в первом случае возникает ошибка компиляции, а во втором случае все работает?

Это, конечно, предупреждение и не ошибка, если ваши параметры компилятора не являются такими, что каждое предупреждение превращается в ошибку. Компилятор не должен отклонять код, потому что it's not ill-formed.

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

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

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

+0

«Объект, названный локальным переменным фантом, заканчивает свою жизнь, когда функция возвращается». Таким образом, он живет до и включает оператор return (следовательно, и его адрес). Это утверждение не удовлетворяет меня, но я согласен с тем, что проблема связана с правилами, описанными в самой конструкции C++. –

Смежные вопросы