Область видимости и возвращаемые значения в C ++ - PullRequest
25 голосов
/ 09 ноября 2008

Я снова начинаю с c ++ и думаю о области видимости переменных. Если у меня есть переменная внутри функции, а затем я возвращаю эту переменную, не будет ли переменная «мертвой», когда она вернется, потому что область действия, в которой она находилась, закончилась?

Я пробовал это с функцией, возвращающей строку, и это сработало. Кто-нибудь может объяснить это? Или, по крайней мере, укажите мне в какое-нибудь место, которое может объяснить это мне, пожалуйста.

Спасибо

Ответы [ 6 ]

42 голосов
/ 09 ноября 2008

Когда функция завершается, происходят следующие шаги:

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

  • Все после фрейма стека указатель отключен. Это разрушает все локальные переменные и аргументы.

  • Возвращаемое значение выталкивается из стек и назначается в качестве значения функции. Если значение функция не назначена ни на что, назначение не происходит, а значение потеряно.

  • Адрес следующей инструкции выполнение выталкивается из стека, и процессор возобновляет выполнение в эта инструкция.

Стек и куча

3 голосов
/ 09 ноября 2008

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

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

3 голосов
/ 09 ноября 2008

Это действительно зависит от того, какую переменную вы возвращаете. Если вы возвращаете примитив, то он возвращается копией, а не ссылкой, поэтому значение копируется в верхнюю часть стека (или, чаще всего, помещается в регистр), где вызывающая функция может его получить. Если вы выделяете объект или память в куче и возвращаете указатель, он не умирает, потому что он находится в куче, а не в стеке. Однако если вы разместите что-то в стеке и вернете это, это будет плохо. Например, любой из них будет очень плохим:

int *myBadAddingFunction(int a, int b)
{
    int result;

    result = a + b;
    return &result; // this is very bad and the result is undefined
}

char *myOtherBadFunction()
{
    char myString[256];

    strcpy(myString, "This is my string!");
    return myString; // also allocated on the stack, also bad
}
3 голосов
/ 09 ноября 2008

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

int funcB() {
  int j = 12;
  return j;
}

void A() {
  int i;
  i = funcB();
}

Значение j (12) копируется и возвращается в i, чтобы я получил значение 12.

2 голосов
/ 09 ноября 2008

Это зависит от типа возвращаемого товара. Если вы возвращаете по значению, создается новая копия переменной для возврата вызывающей стороне. В этом случае вам не нужно беспокоиться о времени жизни объекта, но вам, возможно, придется беспокоиться о стоимости копирования объектов (но, пожалуйста, не преждевременно оптимизируйте - правильность гораздо важнее):

std::string someFunc( std::string& const s)
{
    return s + "copy";
}

Если функция возвращает ссылку, вам нужно быть осторожным с тем, что вы возвращаете, потому что срок ее службы должен превышать срок действия функции, и вызывающая сторона не обязательно сможет delete это сделать, если вы используя new для создания объекта:

std::string& someFunc2( std::string const& s)
{
    return s + "reference to a copy";   // this is bad - the temp object created will 
                                        //  be destroyed after the expression the 
                                        //  function call is in finishes.
                                        //  Some, but not all, compilers will warn 
                                        //  about this.
}

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

2 голосов
/ 09 ноября 2008

Локальная переменная копируется в возвращаемое значение. Конструкторы копирования вызываются для нетривиальных классов.

Если вы вернете указатель или ссылку на локальную переменную, у вас возникнут проблемы - как подсказала ваша интуиция.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...