Unreal Engine 4 http://uengine.ru/forum/ |
|
Указатели и ссылки как аргументы функции http://uengine.ru/forum/viewtopic.php?f=19&t=12097 |
Страница 1 из 1 |
Автор: | Svarog [ 04 ноя 2017, 10:18 ] |
Заголовок сообщения: | Указатели и ссылки как аргументы функции |
Решил раз и навсегда окончательно разобраться в этом базовом вопросе. Нашел хорошие статьи об этом. Например, вот тут все хочень хорошо изложено 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; Или, если разыменование указателя не избежать, то лучше сразу передавать переменную? Заранее благодарен за ответы. |
Автор: | vkd [ 05 ноя 2017, 11:54 ] |
Заголовок сообщения: | |
по первому пункту - функция получит адрес var, а вернет значение. Если Вы хотите, чтобы возвращался адрес - то один из вариантов- объявить ее как int& GetValue1(const int &var) |
Автор: | gary_cho [ 05 ноя 2017, 23:11 ] |
Заголовок сообщения: | |
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; } |
Автор: | Svarog [ 06 ноя 2017, 11:25 ] |
Заголовок сообщения: | |
Спасибо за разъяснения. Таким образом получается следующее... 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); } Вроде как-то так... Я уже всяко разно поигрался, просто не хочется из-за какого-то недопонимания выхватить в будущем кучу проблем с поиском ошибки. |
Автор: | gary_cho [ 06 ноя 2017, 13:38 ] |
Заголовок сообщения: | |
ты скажи что задумал ? |
Автор: | Svarog [ 07 ноя 2017, 10:07 ] |
Заголовок сообщения: | |
Игру делаю :) Хотя в это и сложно поверить. Особенно мне самому. Еще год назад я считал невероятным понять, что же это такое С++... Вот и заполняю дырки в картине мироздания, задавая кучу вопросов, а, иногда, и покупая советы. Над Инвентарем сейчас кроплю. Это же основа всех снов. Третий раз переделываю полностью. Чтобы было быстро и как можно менее затратно. Понятно, что пока 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 Сами же объекты по сути содержат только имя, меши и уникальный для них код, отличающий, собственно, автомат от фонарика. Ну а дальше начнается магия. Как заставить все это функционировать. Алгоритм заполения свободных ячеек с приоритетом на выбранный в данный момент слот занял много времени... Репликация опять же... В данный момент все работает очень хорошо. Выкидывается и берется как надо. И по одному и пачками. Теперь решил довести до около финальной версии компонент-инвентарь, базу и их взаимодействие. А это без указателей сложновато сделать. В принципе уже закончил. Нет предела совершетсву, но нужно двигаться дальше ;) |
Автор: | Deus Ex Machina [ 12 ноя 2017, 06:23 ] |
Заголовок сообщения: | Re: |
Svarog писал(а): Игру делаю :) Хотя в это и сложно поверить. Особенно мне самому. Еще год назад я считал невероятным понять, что же это такое С++... Вот и заполняю дырки в картине мироздания, задавая кучу вопросов, а, иногда, и покупая советы. Над Инвентарем сейчас кроплю. Это же основа всех снов. Третий раз переделываю полностью. Чтобы было быстро и как можно менее затратно. Понятно, что пока 2-3 вещи и 2 клиента это все не критично... Но я хочу заложить очень прочный фундамент для очень большого проекта. Поэтому не спешу. А причем тут указатели? Ссылки и указатели для локальной памяти. Ими ты не разгрузишь сервер или клиента(то есть оно не зависти от кол-ва клиентов). Поэтому поработать с переменной с несколькими параметрами (типа вес, объем, кол-во) ты разницы не увидишь в способах ( то есть core2duo это будет делать без ссылок и указателей так же быстро как и i7 с ссылками и указателями. Масштаб не тот.. Да даже на БП не нативном через виртуальную машину будет один в один по скорости) Только если ты постоянно массивы крутишь или просчитываешь что-то ну очень сложное.Тут стоит задуматься о том что бы как меньше передавать в сеть. |
Автор: | Svarog [ 17 дек 2017, 07:52 ] |
Заголовок сообщения: | |
Использую указатели только для массивов и объектов. Сыылки для всех входных переменных в функцию. Думаю, все-таки есть разница передавать в функцию ссылку или саму переменную. Ровно как и копировать из базы данные, или обращаться к ним по ссылке. Может и не увижу разницы. Но для меня важно понимать, что она есть. Если можно сделать лучше, зачем делать хуже? |
Страница 1 из 1 | Часовой пояс: UTC + 3 часа |
Powered by phpBB® Forum Software © phpBB Group https://www.phpbb.com/ |