Полезное

Мы Вконтакте

Discord канал

#
Аватара пользователя
Пользователь
Сообщения: 23
Решил раз и навсегда окончательно разобраться в этом базовом вопросе.
Нашел хорошие статьи об этом.
Например, вот тут все хочень хорошо изложено
https://teccxx.neocities.org/mx1/pointers.html

Тем не менее, остались вопросы, на которые я надеюсь получить ответ тут.
В примерах ниже, прошу преставить вместо "int", например, очень большой текст.


1. Использование ссылок при передаче переменных в функцию

Код:
int a = 10;

int GetValue1(const int &var){
   
   return var;
}

int b = GetValue1(a);

Если я все правильно понимаю, то в данном случае, при подставлении переменной "a" в функцию "GetValue1", фактически внутри функции используется ссылка на переменную "a".
Вопрос в том, что именно передается в функцию? Большая пребольшая переменная или ее адрес?
Что функция возвращает? Большую переменную или адрес какого-то участка памяти, из которого потом все копируется в "b".

Чтобы понять вопрос, рассмотрим следующий пример.

Если я хочу получить указатель на данную переменную, чтобы не занимать память, то
Код:
 int* c = &GetValue1(a);
Т.е. я получаю переменную из функции (или ее адрес?) и дальше беру адрес этой переменной (или адрес адреса?)?
Мне важно понять, будет ли функция "GetValue1" в данном случае "перекачивать" куда-то данные из "a"?


2. Использование указателей как результат работы функции.

Продолжаем дописывать предыдущий пример.
Код:
int* GetValue2(const int &var){
   
   return &var;
}

int* d = GetValue2(a)

В данном случае, в строке
Код:
return &var;
мы получаем адрес переменной "a" и передаем его дальше в качестве указателя.
Таким образом, переменной "d" фактически присваиается адрес "a", что нам и нужно. Т.е. большая переменная не передается, точно?


3. Использование указателей как результат работы функции и для передачи в функцию.

Код:
int* GetValue3(int *var){
   
   if (*var <= 0){
      
      return nullptr;
   }
   
   return var;
}

int* e = GetValue3(&a)

В данном примере передается адрес переменной "a" в виде указателя, который потом разименовывается для сравнения.
В итоге возвращается указатель на "a", если "a" больше ноля (для примера).
Насколько затрана операция разименования?


Итог:

Пожалуйста ответье на вопросы по тексту выше, и желательно не просто ссылкой на очередной мануал для тех, кому мануалы уже не нужны.
Т.е. где все слишком заумно написано.

И еще вопросы:

Что будет работать быстрее и/или "ошибкоустойчивее"?
Код:
int b = GetValue1(a);
int* c = &GetValue1(a);
int* d = GetValue2(a)
int* e = GetValue3(&a)
Т.е. интересует какой из примеров окажется наиболее приемлимым с точки зрения затрат памяти и быстродействия.

Насколько дорого обойдется потом вот такая операция:
Код:
int f = *c;

Или, если разыменование указателя не избежать, то лучше сразу передавать переменную?

Заранее благодарен за ответы.
Аватара пользователя
Пользователь
Сообщения: 72
по первому пункту - функция получит адрес var, а вернет значение. Если Вы хотите, чтобы возвращался адрес - то один из вариантов- объявить ее как int& GetValue1(const int &var)
Аватара пользователя
Пользователь
Сообщения: 195
1.
Код:
int GetValue1(const int &var)
{   
   return var;
}

функция вернёт копию var, т.е int( var )

Код:
int* c = &GetValue1(a);

тут может упасть, так как вернёт адрес временной переменной на стеке

2. Тут по идее дожна быть ошибка компиляции ты передаёшь константу, значит и должен возвращать const int *, а не int*

3. Для начало нужно по правильно проверить указатель на валидность
Код:
if( !var )
    return nullptr;


операция разименования не затратна

так по-короче
Код:
int * GetValue3( int * var )
{
   
   return ( !var || *var <= 0) ? nullptr : var;
}
Аватара пользователя
Пользователь
Сообщения: 23
Спасибо за разъяснения.

Таким образом получается следующее...

4. Если мне нужна где-то переменнная, небольшая по размеру, то лучше использовать указатель при передаче и на выходе получать копирование результата.
Код:
int GetValue(const int &Var1, const array &Var2){
   // do something
   int Var3 = Var1;

   return Var3;
}



5. Тот же случай, но возвращаемая переменная большая, и я хочу изменить принимаемю переменную
Код:
TArray<int> *GetValue(const int &Var1, TArray<int> *Var2){
   // do something
   Var2->Add(Var1);

   return Var2;
}

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

6. Хотя если нужно просто внести изменение, то можно было бы сделать и так
Код:
void GetValue(const int &Var1, TArray<int> *Var2){
   // do something
   Var2->Add(Var1);
}


Вроде как-то так...
Я уже всяко разно поигрался, просто не хочется из-за какого-то недопонимания выхватить в будущем кучу проблем с поиском ошибки.
Аватара пользователя
Пользователь
Сообщения: 195
ты скажи что задумал ?
Аватара пользователя
Пользователь
Сообщения: 23
Игру делаю :) Хотя в это и сложно поверить. Особенно мне самому.
Еще год назад я считал невероятным понять, что же это такое С++...
Вот и заполняю дырки в картине мироздания, задавая кучу вопросов, а, иногда, и покупая советы.

Над Инвентарем сейчас кроплю. Это же основа всех снов. Третий раз переделываю полностью.
Чтобы было быстро и как можно менее затратно.
Понятно, что пока 2-3 вещи и 2 клиента это все не критично...
Но я хочу заложить очень прочный фундамент для очень большого проекта.
Поэтому не спешу.

1. DataAsset - база, где хранится статическая инфомация.

Формат базы TMap<FGameplayTag, FItemsDatabase> ItemsDataBase;

где:
Имя - в формате FGameplayTag
FItemsDatabase - структура, в которой:

Статические свойста объекта - FGameplayTagContainer ItemPropertyTags
Статические данные объекта - в формате TMap<FGameplayTag, float> ItemData. Размер стака, прочность, урон и все такое прочее.
Текстура - UTexture2D* IconTexture;
Класс дня спауна на игроке - TSubclassOf<class ADreampaxItem> ItemOutfitClass
Класс для спауна на карте - TSubclassOf<class ADreampaxItemPickup> ItemPickupClass

2. ContainerComponent - для непосредственного хранения как инвентаря, так и содержимого всяких ящиков.

Формат TArray<FContainerStack> ContentOfContainer

где FContainerStack - структура:

Имя - FGameplayTag ItemNameTag
Количество - int ItemAmount
Свойства, специфические для конкретной копии (множители) - TArray <FItemFactor> ItemFactors

где FItemFactor опять-таки структура
Имя множителя - FGameplayTag ItemFactorTag
Сам множитель - float ItemFactor


Сами же объекты по сути содержат только имя, меши и уникальный для них код, отличающий, собственно, автомат от фонарика.


Ну а дальше начнается магия.
Как заставить все это функционировать.
Алгоритм заполения свободных ячеек с приоритетом на выбранный в данный момент слот занял много времени...
Репликация опять же...

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

В принципе уже закончил. Нет предела совершетсву, но нужно двигаться дальше ;)
Аватара пользователя
Пользователь
Сообщения: 1297
Svarog писал(а):
Игру делаю :) Хотя в это и сложно поверить. Особенно мне самому.
Еще год назад я считал невероятным понять, что же это такое С++...
Вот и заполняю дырки в картине мироздания, задавая кучу вопросов, а, иногда, и покупая советы.

Над Инвентарем сейчас кроплю. Это же основа всех снов. Третий раз переделываю полностью.
Чтобы было быстро и как можно менее затратно.
Понятно, что пока 2-3 вещи и 2 клиента это все не критично...
Но я хочу заложить очень прочный фундамент для очень большого проекта.
Поэтому не спешу.


А причем тут указатели? Ссылки и указатели для локальной памяти. Ими ты не разгрузишь сервер или клиента(то есть оно не зависти от кол-ва клиентов). Поэтому поработать с переменной с несколькими параметрами (типа вес, объем, кол-во) ты разницы не увидишь в способах ( то есть core2duo это будет делать без ссылок и указателей так же быстро как и i7 с ссылками и указателями. Масштаб не тот.. Да даже на БП не нативном через виртуальную машину будет один в один по скорости) Только если ты постоянно массивы крутишь или просчитываешь что-то ну очень сложное.Тут стоит задуматься о том что бы как меньше передавать в сеть.
_________________
Мои работы.
Youtube Channel
Форум по геймдеву.
Аватара пользователя
Пользователь
Сообщения: 23
Использую указатели только для массивов и объектов.
Сыылки для всех входных переменных в функцию.
Думаю, все-таки есть разница передавать в функцию ссылку или саму переменную.
Ровно как и копировать из базы данные, или обращаться к ним по ссылке.

Может и не увижу разницы. Но для меня важно понимать, что она есть.
Если можно сделать лучше, зачем делать хуже?


Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

UEngine.ru © 2017
Все права защищены. При копировании материалов с сайта, ссылка на первоисточник обязательна.
Яндекс.Метрика
Главная страница