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

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

ua
Offline Offline

« : 25-04-2018 12:56 » 

Код:
Привет форумчане.

Подскажите. Есть у меня функции
[code]
LPCWSTR Function1()
{
    return L"Трям";
}

Работает и возвращает в вызывающий код "Трям"
есть другая

Код:
wstring Function2()
{
    wstring s = wstring(L"Трям");
    return s;
}
Работает и возвращает в вызывающий код "Трям"
есть третья
Код:
LPCWSTR Function3()
{
    wstring s = wstring(L"Трям");
    return s.c_str();
}
ни чего не возвращает.

Вопрос: если нет new то по идее все выделятся на стеке. Почему в одном 1 и 2 случае все возращатся, а в третьем нет.
Если я делаю в третьем случае вместо локальной переменной s использую скажем глобальную переменную то все работает.
Если делаю через переменную в куче то тоже все возращает. Чего я не доганяю?
[/code]
« Последнее редактирование: 25-04-2018 12:58 от Boriska » Записан
darkelf
Молодой специалист

no
Offline Offline

« Ответ #1 : 25-04-2018 15:04 » 

Подскажите. Есть у меня функции
Код: (C)
LPCWSTR Function1()
{
    return L"Трям";
}

Работает и возвращает в вызывающий код "Трям"
На самом деле она возвращает константу, wchar_t*, которая указывает на какую-то область памяти (скорее всего в глобальных переменных только для чтения), в которой хранится "Трям".

есть другая
Код: (C)
wstring Function2()
{
    wstring s = wstring(L"Трям");
    return s;
}
Работает и возвращает в вызывающий код "Трям"
Во втором случае, имхо, при возвращении происходит копирование объекта, и в вызывающей программе Вы пользуетесь копией s. Надеюсь люди знающие C++, если что, меня поправят.

есть третья
Код: (Text) С
LPCWSTR Function3()
{
    wstring s = wstring(L"Трям");
    return s.c_str();
}
ни чего не возвращает.
В этом случае, т.к. объект s не возвращается в вызывающую программу, происходит его освобождение при завершении Function3. В return оказывается указатель, который ссылается на уже освобождённую память. В этом случае программа имеет "неопределённое поведение" и соответственно может как ничего не возвращать, так и форматировать диск или постить во вконтакты и инстаграммы фото любимых котиков при полной луне.
« Последнее редактирование: 25-04-2018 15:09 от darkelf » Записан
Boriska
Помогающий

ua
Offline Offline

« Ответ #2 : 26-04-2018 06:41 » 

1.
Цитата
На самом деле она возвращает константу, wchar_t*, которая указывает на какую-то область памяти (скорее всего в глобальных переменных только для чтения), в которой хранится "Трям".
Код:
        typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character
         typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;
т.е. wchar_t* и LPCWSTR одно и тоже только второй константный.
Но вопрос именно в какую область памяти копируется "Трям" что бы он не затирается по завершению функции?
Опять же вопрос 1 и 2 связаны, они обе куда то кладут "Трям" что он не затирается по завершению функции.
И чем тогда функция 3 отличается от 2. Она тоже куда-то кладет строку, берет указатель на нее и должна бы вернуть, но ....
Записан
darkelf
Молодой специалист

no
Offline Offline

« Ответ #3 : 26-04-2018 07:23 » new

Но вопрос именно в какую область памяти копируется "Трям" что бы он не затирается по завершению функции?
Что-бы было понятнее Function1, на самом деле выглядит так (если перевести с языка ассембллера на C-подобный псевдокод):
Код: (C)
static LPCWSTR tryamstr = L"Трям";

LPCWSTR Function1()
{
  return tryamstr;
}
т.е. в первом случае L"Трям" никуда не копируется, а просто возвращается её адрес. Сама строка находится в секции данных, скорее всего в области доступной только для чтения.

Опять же вопрос 1 и 2 связаны, они обе куда то кладут "Трям" что он не затирается по завершению функции.
Во втором случае компилятор видит, что возвращается объект wstring и, выполняет перенос содержимого wstring s из внутреннего стека функции Fuction2, в переменную указанную в вызывающей функции. Т.е. на самом деле код выглядит примерно так:
Код: (C)
static LPCWSTR tryamstr = L"Трям";
static wstring _temp;

void Function2()
{
  wstring s = wstring(tryamstr);

  _temp = s;
  delete s;
  return ;
}

void caller(void)
{
  wstring rez;

  Function2();
  rez = _temp;

  return ;
}
На самом деле двойного копирования (из s в _temp, а потом из _temp в rez) не происходит. При возврате из функции компилятор сам правильно указывает, как скопировать переменную на стеке wstring s  в переменную вызывающей функции  wstring rez. Более точно могут сказать знатоки C++.

И чем тогда функция 3 отличается от 2. Она тоже куда-то кладет строку, берет указатель на нее и должна бы вернуть, но ....
В третьем случае код выглядит, имхо, так:
Код: (C)
static LPCWSTR tryamstr = L"Трям";

LPCWSTR Function3()
{
  wstring s = wstring(tryamstr);
  LPCWSTR _temp = s.c_str();

  delete s;
  return _temp;
}
В s хранится КОПИЯ tryamstr, а не ссылка на неё. При вызове c_str() возвращается адрес КОПИИ tryamstr, а при вызове delete s весь объект s, и копия tryamstr внутри него уничтожаются и получается, что _temp, который возвращается вызывающей функции, указывает на уже освобождённую область памяти.
« Последнее редактирование: 26-04-2018 08:02 от darkelf » Записан
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines