LINUX.ORG.RU

про возврат из ф-ции в С\С++


0

0

Re all; 1. Если есть char * func () {buf char[30]; .... return buf;}; то получается что возращается мусор. Потому что buf локальная переменная, и память выделенная под нее освобождается по выходу из ф-ции. Так? 2. Если string func() { string s("fdksfksfd"); return s;}; то возвратиться fdksfksfd и все будет ок. Потому что запуститься конструктор копирования и и объект s будет скопирован в объект которому мы делаем присваивание значения функци.Правильно? 3. Если int func () { int fd = 4; return int ;}; а тут как все впорядке? 4.А если int func () { int fd=4;int lf=3; return fd+lf;}; а тут что происходит?

Думаю начинающим программистам этот тред будет полезен . Великие гуру пожалуста расскажите по пунктам 1-4 и если есть какие нить еще грабли или хитрости напишите пожалуйста.

anonymous

1. return buf; возвращает указатель на buf, можно buf пометить как static, тогда все будет ок..ну почти 2. возвращает объект типа string, копию s. 3. возвращает просто число, как и в 1 в принципе. 4. тоже самое.

no1sm ★★
()
Ответ на: комментарий от no1sm

Все зависит от того на каком уровне рассматривать все это.
Если например на ASM то везде возвращается int32.
Числа хранятся непосредственно а не по ссылке соответственно
глюков не происходит. А вот с объектами и с char buf[100]
другая ситуация - действительно buf[100] (возможно) удаляется
из памяти (это зависит от компилятора), а string копируется
за счет operator= либо за счет string(const string &a)
и возвращается ссылка на новый объект.

vahvarh ★★★
()

Чтобы было проще понять, возвращается всгда объект, типа которого указан, в описании функции.

В первом случает этим объектоя является указатель на char, т.е. объекти типа (char*) не сам char, и не массив char[].

Во всех других случаях тоже самое.

Соответственно в первос случае мы получим указатель на то место, где когда-то (во время выполнения функции) находился массив char[]. Его там уже может и не быть. При операции чтения, мы можем получить просто мусор, а при операции записи туда, скорее всего возникнут проблемы. Как написани выше, можно объявить локальный массив как static, тогда изменится лишь то, что при выходе из функции, локальный объект - наш массив не удаляется, а остается.

Иногда это полезно использовать, но всегда надо понимать что происходит.

hapchu ★★
()

прошу прощения за опечатки

hapchu ★★
()

1. buf располагается в стеке, func возвращает указатель на область стека, где располагается buf, однако после возврата из func, эта область используется другими функциями, поэтому - мусор.

2. Формально, да - вызывается конструктор копирования. На практике, для string это не так страшно, как кажется, потому что сама строка не копируется.

3. Тут абсолютно всё в порядке. Особенно учитывая, что int в C++ - не класс.

4. int - это не класс. Никаких конструкторов/деструкторов у него нет, присваивание копированием. Тут будет всё нормально.

watashiwa_daredeska ★★★★
()

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

int func ()

возвращается целое значение

char * func ()

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

string func()

возвращается экземпляр (не указатель!) класса string.

DKorolkov
()
Ответ на: комментарий от watashiwa_daredeska

> 2. Формально, да - вызывается конструктор копирования. На практике,
> для string это не так страшно, как кажется, потому что сама строка
> не копируется.

Почему это? Тут строка - локальная переменная, создается в стеке,
поэтому после завершения функции она разрушается. Перед завершением
работы функции она отдает копию строки тому, кто ее вызывал
(return s;), а свою локальную s потом разрушает. Я не прав?

murla
()

> 4. А если
> int func ()
> {
>     int fd=4;
>     int lf=3;
>     return fd+lf;
> }
> а тут что происходит?

Создается переменная fd и инициализируется значением 4;
создается переменная lf и инициализируется значением 3;
создается переменная с каким-то именем и инициализируется 4+3=7;
значение последней переменной копируется в переменную, которой
  присвается значение func();
наконец, разрушается переменная_с_неизвестным_именем (значение которой равно 7),
затем lf и fd.

murla
()
Ответ на: комментарий от DKorolkov

" string func() возвращается экземпляр (не указатель!) класса string. "

Это с чего бы? Формально возвращается копия объекта. Внутренняя реализация может быть какая угодно.

string& func()

Вот это экземпляр. Вообще все это есть в любом учебнике.

hapchu ★★
()
Ответ на: комментарий от murla

> Тут строка - локальная переменная, создается в стеке, поэтому после завершения функции она разрушается. Перед завершением работы функции она отдает копию строки тому, кто ее вызывал (return s;), а свою локальную s потом разрушает. Я не прав?

Прав, но... Экземпляры класса string содержат char*, указывающий на собственно строку. И если:

string a, b("zzz"); a=b;

то память, где хранится собственно строка "zzz", не копируется. И a, и b будут указывать на один и тот же буффер со строкой.

P.S. По крайней мере, так было в той реализации, что я видел.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от hapchu

> Формально возвращается копия объекта.

А копия это не экземпляр?

string a("aaa"); string b(a);

Сколько тут экземпляров класса string? Является ли b копией a?

> Вот это экземпляр.

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

watashiwa_daredeska ★★★★
()

> Думаю начинающим программистам этот тред будет полезен.

Маловероятно :) Полезнее почитать всеми горячо не любимого Страуструпа. А чтобы досканально разобраться в этом вопросе лучше почитать Хантера, про компиляторы, ибо хотя стандарты на языки С/С++ и есть писатели компиляторов на них поподу забивают :)

KIV
()
Ответ на: комментарий от watashiwa_daredeska

> string a, b("zzz"); a=b;
>
> то память, где хранится собственно строка "zzz", не копируется. И a, и > b будут указывать на один и тот же буффер со строкой.
>
> P.S. По крайней мере, так было в той реализации, что я видел.

Ну это легко проверить

    std::string a = "abc", b;

    b = a;
    a[0] = 'A';

    std::cout << b[0] << '\n';

У меня вывелось, разумеется, 'a' (маленькое). Компилятор gcc-2.95 и
gcc-3.4. Так что здесь у a и b char *s у каждого свой, а не один на
двоих. Мне твоя реализация кажется абсурдом - с какой стати a и b
должны бать вообще чем-то связаны?

murla
()
Ответ на: комментарий от murla

> a[0] = 'A';

А ты посмотри на реализацию, в string переопределяется оператор []. Ты попробуй так сделать:

((char*)a.c_str())[0] = 'A';

> Мне твоя реализация кажется абсурдом - с какой стати a и b должны бать вообще чем-то связаны?

Допустим, у тебя имеется строка. Текстовичок метров на -дцать. И ты решил передать её в функцию unsigned count_words( const string s ). Твои предположения по поводу расхода памяти?

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

> ((char*)a.c_str())[0] = 'A';
> Допустим, у тебя имеется строка. Текстовичок метров на -дцать. И ты
> решил передать её в функцию unsigned count_words( const string s ).
> Твои предположения по поводу расхода памяти?

Ну добро :) Да, я встречался с похожим, только в языке R. Копирование
строки любых размеров (s2 <- s1) происходит мгновенно, то есть
копирование всей строки явно не происходит. Так что же, в таком случае,
происходит при операциии a[0] = 'A'? Старый символ 'a' все равно
сохраняется, раз он выводится при cout << 'b[0]'?

Теперь со следующим:
string func()
{
    string s("fdksfksfd");
    return s;
}

Для s должен вызываться как конструктор, так и деструктор, который
должен полностью разрушить s. Но значение строки возвращается и
где-то сохраняется. Но как же так, был же вызван деструктор? :-)

murla
()
Ответ на: комментарий от watashiwa_daredeska

> Допустим, у тебя имеется строка. Текстовичок метров на -дцать. И ты
> решил передать её в функцию unsigned count_words( const string s ).
> Твои предположения по поводу расхода памяти?

А если текстовичок еще на пару порядков больше? Ты все равно его будешь
засасывать сразу в одну строку? Я вообще-то с текстом построчно работаю,
как это не странно :)

murla
()
Ответ на: комментарий от murla

> Я вообще-то с текстом построчно работаю, как это не странно

Ok. Пусть построчно. Но ты посчитай лишние накладные расходы, в приведённом мной случае, на дополнительные выделения/освобождения памяти, копирование строкового буффера. Особенно, если работать с текстовичком на пару порядков больше построчно :)

watashiwa_daredeska ★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.