указатель, возвращаемый функцией из библиотеки SDL - PullRequest
0 голосов
/ 31 января 2019

Я следую руководству по созданию игрового движка на YouTube, в котором используется SDL.Я изучил многие вещи, связанные с C ++, и занимался более глубоким погружением, связанным с указателями (необработанными и умными), а также изучал стек и кучу.в учебнике есть небольшая функция, которая возвращает указатель.Я не понимаю, как этот указатель все еще доступен во время выполнения кода?Вот рассматриваемый код.

SDL_Texture* TextureManager::LoadTexture(const char* texture)
{
  SDL_Surface* tempSurface = IMG_Load(texture);
  SDL_Texture* tex = SDL_CreateTextureFromSurface(Game::renderer, 
      tempSurface);
  SDL_FreeSurface(tempSurface);

  return tex;
}

этот фрагмент кода содержит информацию об указателях повсюду ...

Теперь, чтобы узнать об этом материале, я попытался создать нечто подобное, чтобы посмотреть, как работает памятьс указателями из функции, которую я создал.

int* test() {
  int num = 5;
  return #
}

int main()
{
  int* ptr = nullptr;
  ptr = test();
  std::cout << "Hello World!\n";
  int testArray[5];
  int i = 1;
  testArray[0] = 1;
  testArray[1] = 2;
}

информация об указателях уничтожается при вызове int i.Есть ли что-то, чего мне не хватает, почему это не работает так же, как функция выше?

Ответы [ 4 ]

0 голосов
/ 31 января 2019

В C / C ++ есть 4 основных класса хранения:

  1. Автоматически: локальные объекты - обычно создаваемые в стеке - разрушаются, как только область их действия достигает своего конца.Область видимости обычно находится в теле функции, поэтому все автоматические объекты, созданные внутри функции, уже разрушаются, когда функция возвращается;сюда входят и аргументы функции.
  2. Внутренний / статический: срок их службы больше, чем у большинства автоматических переменных.Однажды построенные, они живут, пока не будет достигнута конечная точка программы;когда они автоматически уничтожаются.Эти объекты видны / доступны только в модуле (модуль перевода) /function/scope.
  3. Глобальный / внешний: эти объекты живут дольше, чем все объекты в 1-м или 2-м классах выше.Они создаются после запуска и уничтожения программы непосредственно перед ее завершением, когда все автоматические и внутренние объекты уже мертвы.
  4. Динамический / куча: они имеют гибкий срок службы.Они могут быть созданы в любое время во время выполнения программы и уничтожены в любое время после.Как правило, они нуждаются в ручной утилизации, если только надлежащие умные указатели не используются для автоматизации управления их продолжительностью жизни.Одним из распространенных источников ошибок является неправильное их устранение.

Поэтому обычно возвращение ссылки / указателя на любые неавтоматические объекты - это нормально.

0 голосов
/ 31 января 2019

Итак, test() нарушает это правило прямо здесь .

Я, к сожалению, не могу найти достаточно исследований, к моему удовлетворению, почему это правило, но я опубликую свое подозрение.

num - локальная переменная.Локальные переменные размещаются в стеке.В ту минуту, когда функция завершает выполнение, локальные переменные (т.е. num) «выталкиваются» из стека.То есть они уничтожены.

Переменные, которые выделяются с помощью таких вещей, как malloc() или ключевое слово new, размещаются в куче.Куча не уничтожается во время выполнения программы

Адрес, хранящийся в num в таком случае, как это:

int *num = new int(37);

- это адрес накуча.Он действителен даже после того, как функция завершит выполнение.Таким образом, вы можете использовать его после завершения функции.

0 голосов
/ 31 января 2019

В дополнение к ответу других, SDL - это C (не C ++) API, поэтому он не имеет RAII, что означает, что нет такой среды, которая автоматически вызывает конструктор и деструктор.

Вам необходимо вызвать SDL_DestroyTexture чтобы освободить текстуру.В противном случае это приведет к утечке памяти в отличие от локальных переменных.

Вы можете концептуально представить

  • SDL_CreateTextureFromSurface() (или другой API генерации текстур) как new SDL_Texture
  • SDL_DestroyTexture(texture) как delete texture
0 голосов
/ 31 января 2019

В вашей функции test, num является локальной переменной.Он уничтожается к концу test().

. Вам нужно выделить целое число в test, чтобы оно заработало.В этом случае право собственности на указатель передается вам: вам нужно удалить его.

int* test() {
  int* num = new int(5);
  return num;
}

int main() {
  int* ptr = test();
  std::unique_ptr<int> int_deleter(ptr);
  std::cout << "Hello World!\n" << *ptr;
}

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

class A {
public:
  A() : num(new int(5)) {}
  virtual ~A () { delete num; }

  // `A` keeps the ownership of the pointer.
  const int* GetNum() const { return num; }

private:
  int* num;
}

int main() {
  A a;
  std::cout << *a.GetNum() << std::endl;
}

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

...