Struktury i klasy: kopia czy referencja
Struktura przekazana do funkcji jest kopiowana, obiekt klasy nie. Skąd biorą się zmiany, które znikają, i te, które pojawiają się nieoczekiwanie.
1 fragment kodu z tej strony przeszedł przez kompilator MetaEditor build 6090, 2026-08-05.
Programiści przychodzący do MQL5 z C++ często traktują słowa kluczowe struct i class jako synonimy, różniące się jedynie domyślnym modyfikatorem dostępu (public dla struktur, private dla klas). W C++ tak właśnie jest. W MQL5 jednak ta różnica jest fundamentalna i dotyczy samego modelu pamięci. Niezrozumienie tego faktu prowadzi do wycieków pamięci, błędów "dangling pointers" i drastycznych spadków wydajności.
W MQL5 struktury są typami wartościowymi (Value Types). Kiedy przypisujesz jedną strukturę do drugiej, MQL5 wykonuje głęboką kopię (deep copy) danych bit po bicie. Z kolei klasy są typami referencyjnymi (Reference Types). Klasa zawsze jest tworzona na stercie (heap) za pomocą new, a przypisanie obiektu do innej zmiennej kopiuje jedynie wskaźnik (adres) do tego samego obiektu w pamięci.
Pstryczek na stercie: Kiedy używać czego?
W MQL5 struktury nie mogą dziedziczyć po innych strukturach (mogą jedynie implementować interfejsy), nie mają wirtualnych funkcji i nie można użyć dla nich słowa new. Są idealne do lekkich kontenerów na dane. Klasyczne struktury z API MQL5, takie jak MqlTradeRequest czy MqlRates, to właśnie typy wartościowe. Przypisanie MqlRates rates1 = rates2 jest bezpieczne i szybkie, o ile struktura nie zawiera w sobie dynamicznych tablic.
Problem pojawia się, gdy w strukturze umieścimy tablicę dynamiczną (np. double arr[]). Wtedy kopia struktury skopiuje referencję do tej samej tablicy! Jest to tzw. płytka kopia (shallow copy). Modyfikacja elementów w tablicy w jednej strukturze zmieni je w drugiej.
// STRUKTURA - typ wartościowy
struct SConfig {
int magic;
double lot;
};
// KLASA - typ referencyjny
class CStrategy {
int id;
public:
CStrategy(int i) { id = i; }
void PrintId() { Print("ID: ", id); }
};
void OnStart() {
SConfig cfg1;
cfg1.magic = 100;
// Tworzy niezależną kopię. Bezpieczne.
SConfig cfg2 = cfg1;
cfg2.magic = 200; // cfg1.magic wciąż wynosi 100!
CStrategy *strat1 = new CStrategy(1);
// Kopiuje WSKAŹNIK, nie sam obiekt!
CStrategy *strat2 = strat1;
strat2 = new CStrategy(2); // strat1 nadal wskazuje na obiekt 1
// Aby skopiować obiekt, trzeba napisać własny konstruktor kopiujący
// lub przeciążyć operator przypisania (wymaga referencji &)
delete strat1;
delete strat2;
}