Подтвердить что ты не робот

Функция в С++ возвращается по значению или по ссылке?

Когда функция (вызываемая) возвращает количество функции вызывающего, возвращается ли она значение или по ссылке?

Дело в том, что я написал функцию, которая строит очень большой вектор при вызове. Я хочу вернуть этот большой вектор в вызывающую функцию (в данном случае main()) с помощью постоянной ссылки, чтобы я мог выполнить некоторую дальнейшую обработку на ней.

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

struct node{

string key;
int pnum;
node* ptr;
}

vector< vector<node> > myfun1(/*Some arguments*/)
{

/*Build the vector of vectors. Call it V*/

return v;

}

int main(void)
{
a=myfun1(/* Some arguments */)
}
4b9b3361

Ответ 1

Функции С++ могут возвращаться по значению, по ссылке (но не возвращать локальную переменную по ссылке) или указателем (опять же, не возвращать локальный указатель).

При возврате по значению компилятор может часто выполнять оптимизации, которые делают его одинаково быстрым, как возврат по ссылке, без проблемы оборванных ссылок. Эти оптимизации обычно называются "Оптимизация возвращаемого значения (RVO)" и/или "Оптимизация наименованных возвращаемых значений (NRVO)".

Другой способ для вызывающего пользователя предоставить пустой вектор (по ссылке) и выполнить его функцию. Тогда ему не нужно ничего возвращать.

Вы обязательно должны прочитать это сообщение в блоге: Хотите скорость? Перейдите по значению.

Ответ 2

По умолчанию все в C/С++ передается по значению, включая тип возвращаемого значения, как в примере ниже:

T foo() ;

В С++, где типы обычно считаются типами значений (т.е. они ведут себя как типы int или double), дополнительная копия может быть дорогостоящей, если построение/уничтожение объекта не является тривиальным.

С С++ 03

Если вы хотите вернуться по ссылке или указателем, вам нужно изменить тип возврата на:

T & foo() ;  // return a reference
T * foo() ;  // return a pointer

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

Если вы не можете гарантировать, что объект по-прежнему существует после возврата, ваше единственное решение - либо:

void foo(T & t) ;

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

С С++ 11

Теперь, если у вас есть возможность работать с С++ 0x/С++ 11, то есть с компилятором, который поддерживает r-values ​​ссылки/перемещение семантики, если ваш объект имеет правильный конструктор/оператор (если ваш объект исходит из стандартной библиотеки, то он в порядке), тогда дополнительная временная копия будет оптимизирована, и вы можете сохранить обозначение:

T foo() ;

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

Ответ 3

Он возвращается тем, что вы объявляете возвращаемым типом. vector<int> f(); и vector<int>& f(); возвращаются по значению и ссылке соответственно. Тем не менее, было бы серьезной ошибкой возвращать ссылку на локальную переменную в функции, поскольку она будет удалена при выходе из области действия.

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

Ответ 4

Функция вернет то, что вы скажете, чтобы вернуться. Если вы хотите вернуть vector, то он будет скопирован на удержание переменной вызывающим. Если вы не зафиксируете этот результат по ссылке const, в этом случае нет необходимости его копировать. Существуют оптимизации, которые позволяют функциям избегать этого дополнительного copy-constructon, поместив результат в объект, который будет удерживать возвращаемое значение. Вы должны прочитать это перед изменением дизайна для производительности:

http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

Ответ 5

С++ может возвращаться либо по ссылке, либо по значению. Если вы хотите вернуть ссылку, вы должны указать это как часть возвращаемого типа:

std::vector<int> my_func(); // returns value
std::vector<int>& my_func(); // returns reference
std::vector<int> const& my_func(); // returns constant reference

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

Если вы хотите "создать" большой вектор внутри функции, а затем вернуть его без копирования, самый простой способ - передать вектор в функцию в качестве эталонного параметра:

void fill_vector(std::vector<int> &vec) {
    // fill "vec" and don't return anything...
}

Также обратите внимание, что в недавно ратифицированной новой версии стандарта С++ (известной как С++ 0x или С++ 11) возврат локального вектора по значению из функции не будет фактически копировать вектор, он будет эффективно перемещен в новое место. Код, который делает это, выглядит идентично коду из предыдущих версий С++, который может быть вынужден скопировать вектор. Проконсультируйтесь с вашим компилятором, чтобы узнать, поддерживает ли он "семантику перемещения" (часть стандарта С++ 11, которая делает это возможным).

Ответ 6

Как и большинство вещей на С++, ответ "зависит от того, как вы определили функцию".

Значение по умолчанию для языка является возвратом по значению. Простой вызов типа "double f()" всегда будет возвращать число с плавающей запятой по значению. Однако вы можете возвращать значения по указателю или по ссылке - вы просто добавляете дополнительные символы '&' или '*' к типу возврата:

// Return by pointer (*)
T* f();

// Return by reference (a single '&')
T& f();

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

// Return by 'parameter' (a logical reference return)
void f(T& output);

Теперь у выхода есть реальное имя, и мы ЗНАЕМ, что он выдержит вызов, потому что он должен существовать до того, как будет выполнен вызов "f". Это шаблон, который вы часто увидите на С++, особенно для таких вещей, как заполнение STL std::vector. Его уродливый, но до появления С++ 11 он часто был быстрее, чем просто возврат вектора по значению. Теперь, когда возврат по значению является более простым и быстрым даже для многих сложных типов, вы, вероятно, не увидите много функций, следующих за шаблоном возвращаемого параметра ссылки за пределами старых библиотек.

Ответ 7

Все переменные, определенные в стеке, очищаются при выходе. Чтобы вернуть переменную, вы должны выделить ее в куче, которую вы используете с новым ключевым словом (или malloc).

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