@Mr-Governor
Губернирую

Где создается копия объекта возвращаемая функцией?

Проблема такая, я не понимаю где создается временная копия объекта. Мне сказали, она создается в стеке, но в стеке уже будет лежать адрес и локальные объекты, куда складывать временный объект? Теперь у меня сложилась следующая картина.
Приведу для примера код:

#include <iostream>
using namespace std;

class samp {
public:
  int a;
};

samp func() //Функция возвращающая локальный объект
{
  samp ob2;
  ob2.a=255;
  return ob2;
}

int main()
{
setlocale(0,"");
    samp ob1;
    ob1 = func();

system("pause");
return 0;
}


При создании объекта ob1 он попадает в стек, вот наш стек:

СТЕК:
__________
ob1
__________


Затем, вызывается функция func(), предварительно сохранив адрес для возврата в тот же стек.
Функция func() создает объект ob2, который то же ложится в стек.
СТЕК:
__________
- ob1
- адрес для возврата
- ob2
__________


Затем, func() кладет в ob2.a значение 255, и для возврата создает временную копию объекта.
СТЕК:
__________
- ob1
- адрес для возврата
- ob2
- ob2 временный
__________


Функция func() завершается и уничтожает свои локальные объекты.
Но! Это же стек.. Как он удалит ob2 и вернется по адресу если вначале лежит временный объект!?

Допустим, программа делает так:

СТЕК:
__________
- ob1
- XXX (Удалено)
- XXX (Удалено)
- ob2 временный
__________


Затем в main() ob1 забирает свое значение у "ob2 временный", хотя стек уже и не стек, и "ob2 временный" тоже удаляется.

СТЕК:
__________
ob1
__________


А если создать временный объект после раскрутки стека и возвращения в main(), то ob2 будет уже освобожден.

Вопрос:
- Что я ни так понимаю?
  • Вопрос задан
  • 191 просмотр
Решения вопроса 1
15432
@15432
Системный программист ^_^
Вот здесь всё зависит от разработчиков компиляторов!

Конкретно ваш пример скомпилировался в очень простой вариант, где функция возвращает int, который затем присваивается и всё.

Я чуть усложнил задачу компилятору, чтобы он не смог сделать оптимизацию:

class samp {
public:
  int a;
  int b[0x100];
};

samp func() //Функция возвращающая локальный объект
{
  samp ob2;
  ob2.a=255;
  for (int i = 0; i < 0x100; i++)
  {
      ob2.b[i] = i;
  }
  return ob2;
}


Что получилось после компиляции в MS Visual Studio 2008 (мой основной инструмент):
для чистоты эксперимента - Debug версия, без оптимизаций
samp * func(samp * result_ptr)
{
  samp ob2;
  ob2.a=255;
  for (int i = 0; i < 0x100; i++)
  {
      ob2.b[i] = i;
  }
  memcpy(result_ptr, &ob2, sizeof(samp));
  return result_ptr;
}

int main()
{
    samp ob1;
    samp result;
    samp temp;
    samp * retval;
    retval = func(&result);
    memcpy(&temp, retval, sizeof(samp));
    memcpy(&ob1, &temp, sizeof(samp));
    return 0;
}


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

P.S. samp? san andreas multiplayer?
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы