Область видимости и возвращаемые значения в C ++

StackOverflow https://stackoverflow.com/questions/275214

  •  07-07-2019
  •  | 
  •  

Вопрос

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

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

Спасибо

Это было полезно?

Решение

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

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

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

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

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

Стек и куча

Другие советы

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

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

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

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

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

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
}

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

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

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

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

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

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.
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top