Передача параметров или глобальные переменные

 
Когда пишу код, стою перед выбором: прописать несколько глобальных переменных вначале и потом их использовать в любом месте кода или в отдельных частях/функциях объявлять новые переменные, а потом воспользоваться передачей параметров, т.е. в каждой отдельной функции пользоваться своими переменными. Какие преимущества можно выделить у того и другого способа? Особенно относительно производительности.
 
Marys_fals:
Чем локальней, тем лучше.
 
Лучше новые объявить переменные и корректнее и на будущие билды лучше. Код живучее будет, по опыту)
 

Как "правило хорошего тона": каждая функция использует свои локальные переменные для получения входных данных, и возвращает какой-либо результат. Вот этот результат можете присвоить глобальной переменной. Ну и передачу параметров по ссылке ещё никто не запрещал. Это позволит вернуть из функции несколько различных результатов, даже разных типов.

Таким образом, функция будет "универсальным кирпичиком" для построения совершенно разных логических конструкций.
И ещё: никто не запрещает перегрузку функций: несколько функций с одним названием, но с различными входными параметрами, как по количеству, так и по типу.

Всё для вашего удобства ;)

 

Marys_fals, на мой взгляд, глобальных переменных надо всемерно избегать.  Их минусы хорошо расписаны в букварях. Из того, что помню:

  • Когда видишь глобальную переменную, даже при ее хорошем названии далеко не всегда можно понять, где она меняется, какие участки кода могут на нее влиять.
  • И наоборот, трудно понять, на какие участки кода отразится изменение глобальной переменной.
  • Как следствие - если ошибка затрагивает глобальную переменную - ее очень трудно отловить, поскольку она начинает влиять сразу на многие места программы.
  • Сложность повторного использования кода. Правильно написанный класс легко переносится в другой проект. Если же он использует глобальные переменные, их приходится "тянуть" за ним, и есть велика опасность, что придется тянуть и другие участки кода.
  • Затрудняется тестирование отдельных классов, поскольку не всегда можно отследить, все ли используемые глобальные переменные проинициализированы верно.

Вот, примерно так.

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

 
Поняла, всем спасибо!)
 
Marys_fals:
Когда пишу код, стою перед выбором: прописать несколько глобальных переменных вначале и потом их использовать в любом месте кода или в отдельных частях/функциях объявлять новые переменные, а потом воспользоваться передачей параметров, т.е. в каждой отдельной функции пользоваться своими переменными. Какие преимущества можно выделить у того и другого способа? Особенно относительно производительности.

Как бывший embedded программист, много программировал на ассемблере и немного в курсе, как компилятор генерит машинный код функци. Конечно, при любой передаче параметров, хоть по ссылке, хоть напрямую происходят дополнительные операции по упаковке-распаковке этих параметров. Я разрабатывал критичные по скорости приложения, так что старались для критичных по таймингу функций делать переменые глобальными и вообще переписывали их на ассемблере, т.к. компилятор всегда вставляет в функцию дополнительный код, пролог и эпилог. Думаю, у MQ все примерно так же.

С другой стороны, а оно того стоит? Мусорная куча глобальных переменных не есть гуд, а прирост в скорости обычно очень незначителен, конечно, если тело функции не a=b+c; Но для таких простых функций вообще проще использовать макросы с параметрами.

Короче, надо смотреть по ситуации.

P.S Кстати, доступ к полям структуры или класса всегда медленнее, чем просто к набору таких же переменных. Ну и что? Я использую классы, это удобно и переносимо, и чихать мне на эти доли процента быстродействия, проще новый комп купить ))

 
VDev:

Как бывший embedded программист, много программировал на ассемблере и немного в курсе, как компилятор генерит машинный код функци. Конечно, при любой передаче параметров, хоть по ссылке, хоть напрямую происходят дополнительные операции по упаковке-распаковке этих параметров. Я разрабатывал критичные по скорости приложения, так что старались для критичных по таймингу функций делать переменые глобальными и вообще переписывали их на ассемблере, т.к. компилятор всегда вставляет в функцию дополнительный код, пролог и эпилог. Думаю, у MQ все примерно так же.

С другой стороны, а оно того стоит? Мусорная куча глобальных переменных не есть гуд, а прирост в скорости обычно очень незначителен, конечно, если тело функции не a=b+c; Но для таких простых функций вообще проще использовать макросы с параметрами.

Короче, надо смотреть по ситуации.

P.S Кстати, доступ к полям структуры или класса всегда медленнее, чем просто к набору таких же переменных. Ну и что? Я использую классы, это удобно и переносимо, и чихать мне на эти доли процента быстродействия, проще новый комп купить ))

Спасибо))
 
Использовать переменные, объявленные глобально и инициализированные в OnInit() иногда очень полезно. В mql4/mql5 полно функций, которые "дорого" дёргать каждый раз в коде, например SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN) или тому подобные, которые не меняются в процессе работы советника/индикатора. Лучше их значение присвоить сразу переменной и дергать переменную, особенно если есть необходимость использовать их на каждом тике.
 

Не учите девушку плохому)))

По пунктам:

  1. Глобальная переменная - ЗЛО. Каждое введение глобальной переменной должно быть строго обосновано. Почему? Писать много и долго, кому интересно сами гуглите и статьи на эту тему читайте.
  2. Передача по ссылке (не константной) и изменение внешней переменной внутри функции. Очень спорное архитектурное решение, в стиле С. Да, не всегда можно этого избежать, но лучше не надо.
  3. Возврат нескольких значений из функций. Можно возвращать структуру, но есть одно но. В mql нет copy elision optimization. Why? I don't know). В результате получаем: 
struct A{
   int a;
   A() {Print(__FUNCSIG__);}
   A(int _a):a(_a){Print(__FUNCSIG__);}
   A(const A& o):a(o.a){Print(__FUNCSIG__);}
   void operator =(const A& o) {Print(__FUNCSIG__); a=o.a;}
};

A Foo(int a){
   A ret(a);
   return ret;
}

void OnStart(){
   A a=Foo(0);
}

2023.05.02 13:35:10.198 test (AUDJPY,H1)        A::A(int)
2023.05.02 13:35:10.198 test (AUDJPY,H1)        A::A(const A&)
2023.05.02 13:35:10.198 test (AUDJPY,H1)        A::A(const A&)

вместо плюсовых:

#include <iostream>

#define DLOG(p) std::cout<<p<<std::endl;

struct A {
        int a;
        A() { DLOG(__FUNCSIG__); }
        A(int _a) :a(_a) { DLOG(__FUNCSIG__); }
        A(const A& o) :a(o.a) { DLOG(__FUNCSIG__); }
        A(A&& o) noexcept :a(o.a) { DLOG(__FUNCSIG__); }
        A& operator =(const A& o) { DLOG(__FUNCSIG__); a = o.a; }
        A& operator =(A&& o) noexcept { DLOG(__FUNCSIG__); a = o.a; }
};

A Foo(int a) {
        A ret(a);
        return ret;
}

int main() {
        auto a = Foo(0);
}

------- Это результат работы -----------
__cdecl A::A(int)


ЗЫ. п. 3 это для разработчиков.

 

Храните "глобальные" переменные в файле(ах):

  • настройки
  • состояния объектов
  • ...

Причина обращения: