Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Не понятно  (Прочитано 11024 раз)
0 Пользователей и 1 Гость смотрят эту тему.
KurT
Гость
« : 26-05-2005 19:51 » 

Может и глупый вопрос, но всё же.
Код:
#include <iostream>

using namespace std;

int& Fn(){
int i = 20;
return i;
}

int main(){
int& u = Fn();
cout<<u<<endl;
return 0;
}
Насколько я знаю, такая функция опасна и возвращает ссылку на то, чего нет. Так почему на экран выводится 20, память не очищается?
P.S. компилятор Visual Studio .NET
Записан
Гром
Птычк. Тьфу, птычник... Вот!
Готовлюсь к пенсии

il
Offline Offline
Пол: Мужской
Бодрый птах


« Ответ #1 : 26-05-2005 20:13 » 

Память не очищается никогда. Просто в мультитаковой системе есть маленький ньюанс.
В данном конкретном случае все процедуры скореевсего происходят в один - максимум два контентных окна, т.е. за это время успеваешь отработать только ты и все либо один раз еще одна программа запущенная в винде...

А когда ты делаешь такое при нормальной реальной процедуре - ты возвращаешь только указатель на память которая ОБОЗНАЧАЕТСЯ ПУСТОЙ, а не очищается, и при плотной работе с памятью происходит запись в это место другой инфы. Совсем не 0.
Записан

А птичку нашу прошу не обижать!!!
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #2 : 26-05-2005 20:41 » 

Вот реальный ассемблерный код, который генерирует VC++ 6.0 на твою функцию int& Fn()
Код:
00401560   push        ebp
00401561   mov         ebp,esp
00401563   sub         esp,44h
00401566   push        ebx
00401567   push        esi
00401568   push        edi
00401569   lea         edi,[ebp-44h]
0040156C   mov         ecx,11h
00401571   mov         eax,0CCCCCCCCh
00401576   rep stos    dword ptr [edi]
6:    int i = 20;
00401578   mov         dword ptr [ebp-4],14h
7:    return i;
0040157F   lea         eax,[ebp-4]
8:    }
00401582   pop         edi
00401583   pop         esi
00401584   pop         ebx
00401585   mov         esp,ebp
00401587   pop         ebp
00401588   ret
Начало и концовка почти у всех функций стандартна.
Все статические переменные, которые иницилизируются внутри функций, размешаются в стэке. Что илюстрируют данные команды. При этом сам стэк откатывается вниз на длину блока статических переменных.
00401561   mov         ebp,esp
00401563   sub         esp,44h

Доступ ко всем переменным осушествляется через регистр ebp.
Пример
6:    int i = 20;
00401578   mov         dword ptr [ebp-4],14h

Блок статических переменных иницилизируется числом 0xCCCCCCCC
00401569   lea         edi,[ebp-44h]
0040156C   mov         ecx,11h
00401571   mov         eax,0CCCCCCCCh
00401576   rep stos    dword ptr [edi]

Теперь, когда ты выходиш из функции, стэк остаётся на прежней позиции, что и была до входа в функцию.
00401585   mov         esp,ebp
00401587   pop         ebp
00401588   ret
Но память осталась проиницилизированной числом 20. Теперь до следуюшего запуска любой функции в твоем процессе, память будет содержать это число. После запуска, уже никто не сможет гарантировать, что там будет
« Последнее редактирование: 26-05-2005 20:45 от Finch » Записан

Не будите спашяго дракона.
             Джаффар (Коша)
Finch
Спокойный
Администратор

il
Offline Offline
Пол: Мужской
Пролетал мимо


« Ответ #3 : 26-05-2005 21:11 » 

Теперь посмотрим что происходит в программе:
Код:
004015A0   push        ebp
004015A1   mov         ebp,esp
004015A3   sub         esp,44h
004015A6   push        ebx
004015A7   push        esi
004015A8   push        edi
004015A9   lea         edi,[ebp-44h]
004015AC   mov         ecx,11h
004015B1   mov         eax,0CCCCCCCCh
004015B6   rep stos    dword ptr [edi]
11:   int& u = Fn();
004015B8   call        @ILT+345(Fn) (0040115e)
004015BD   mov         dword ptr [ebp-4],eax
12:   cout<<u<<endl;
004015C0   push        offset @ILT+195(std::endl) (004010c8)
004015C5   mov         eax,dword ptr [ebp-4]
004015C8   mov         ecx,dword ptr [eax]
004015CA   push        ecx
004015CB   mov         ecx,offset std::cout (0047be90)
004015D0   call        @ILT+250(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004010ff)
004015D5   mov         ecx,eax
004015D7   call        @ILT+480(std::basic_ostream<char,std::char_traits<char> >::operator<<) (004011e5)
Начало функции стандартное, поэтому не будем разбирать.
Заходим в  функцию Fn  и после этого записываем содержимое регистра EAX себе в переменную (в этом регистре хранится адрес памяти).
11:   int& u = Fn();
004015B8   call        @ILT+345(Fn) (0040115e)
004015BD   mov         dword ptr [ebp-4],eax
Затем уже выводим на печать,
004015C0   push        offset @ILT+195(std::endl) (004010c8)
004015C5   mov         eax,dword ptr [ebp-4]
004015C8   mov         ecx,dword ptr [eax]
004015CA   push        ecx
004015CB   mov         ecx,offset std::cout (0047be90)
Хотя тут и играемся со стэком 004015C0   push        offset @ILT+195(std::endl) (004010c8)
Но все равно  на не достаточную глубину, чтобы затереть наше значение.
Записан

Не будите спашяго дракона.
             Джаффар (Коша)
LP
Помогающий

ru
Offline Offline

« Ответ #4 : 31-05-2005 15:39 » 

#include <iostream>

using namespace std;

int& Fn(){
int i = 20;
return i;
}

void Fn2()
{
int i1=525;
}

int main(){
int& u = Fn();
Fn2();
cout<<u<<endl;
return 0;
}
Записан

Если эта надпись уменьшается, значит ваш монитор уносят
LP
Помогающий

ru
Offline Offline

« Ответ #5 : 12-06-2005 11:34 » new

Извиняюсь за свой предыдущий пост. Просто когда отправлял соединение разорвалось, т.к. мое время закончилось. Думал сообщение так и не отправилось... только сейчас заметил, что только отрывок дошел (или модераторы подправили).

Насколько помню, я хотел сказать KurT'у следующее:
все переменные которые создаются в теле функции помещаются в стек, а после
окончания ее работы эта память помечается свободной, поэтому она рано или поздно может быть
использована для других целей и переменные на которые ты возвращаешь ссылку затрутся.
Как это происходит в вышеприведенной программе (выводится 525). Таким образом возвращать такую ссылку конечно опасно.

Конечно ситуация уже была объяснена Громом и Finch'ем.
Но мне кажется что так оно более понятно (мне виднее я все-таки сам новичок Улыбаюсь )
« Последнее редактирование: 20-12-2007 19:14 от Алексей1153++ » Записан

Если эта надпись уменьшается, значит ваш монитор уносят
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines