2008-11-08 3 views
20

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

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

Благодаря

ответ

37

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

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

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

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

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

The stack and the heap

2

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

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

3

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

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

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

Значение J (12) копируются и возвращается в I, так что я буду получать значение 12.

3

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

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 
} 
+0

Я на самом деле возвращает строку .. это не совсем массив, но я заявляю это в функции, как так: строка funcnam (Parms ...) { строка тест; <код ... код> return string; } И это нормально – AntonioCS 2008-11-08 21:48:23

+0

Если это фактический строковый объект, он отлично работает, потому что он получает выделение в куче, а не в стеке. В плохом примере выше myString на самом деле не объект, а только стандартный массив символов. Статья CMS Stack and Heap очень хорошая, вы должны дать ей прочитать :) – 2008-11-08 21:52:44

3

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

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

0

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

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

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

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