• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Dlaczego ten konstruktor jest lepszy?

VPS Starter Arubacloud
0 głosów
347 wizyt
pytanie zadane 8 maja 2018 w C i C++ przez Alan Hudela Początkujący (340 p.)

Witajcie. Na zajęciach ze struktur danych prowadzący nam ostatnio powiedział, że wcześniej nas okłamywał i tak naprawdę to konstruktory się powinno pisać w drugi z poniżej podanych sposobów. Dlaczego tak jest? Jakie są tego plusy? Pytałem Pana ale niezbyt zrozumiałem to co powiedział :(

Z góry dzięki :)

// Pierwszy sposób
Sznur::Node::Node(int d, Node* n)   // 1
{
    val = d;
    next = n;
}

// Drugi sposób
Sznur::Node::Node(int d, Node *n): val(d), next(n) {}

 

komentarz 9 maja 2018 przez JAKUBW Nałogowiec (33,470 p.)
Tutaj jest to fajnie wytłumaczone z przykładem https://youtu.be/1nfuYMXjZsA

5 odpowiedzi

+1 głos
odpowiedź 9 maja 2018 przez mokrowski Mędrzec (155,460 p.)
wybrane 31 maja 2018 przez Alan Hudela
 
Najlepsza

Chyba trochę komplikujecie w zasadzie prostą sprawę. Bez opisu.. kod:

#include <iostream>

// Usuwaj i dodawaj komentarz w linii 6
// by zobaczyć róźnicę pomiędzy inicjalizacją przez
// listę inicjalizacyjną i bez.
//#define INIT_LIST

struct Checker {
    Checker() {
        std::clog << "default constructor Checker\n";
    }
    Checker(int a): a{a} {
        std::clog << "int arg constructor Checker\n";
    }
private:
    int a;
};

struct MyClass {
#ifdef INIT_LIST
    MyClass(int a): checker{a} {
    }
#else
    MyClass(int a) {
        checker = a;
    }
#endif
private:
    Checker checker;
};

int main() {
    MyClass myClass{42};
}

Konsekwencją takiego działania jest konieczność inicjalizacji atrybutów stałych w liście inicjalizacyjnej.

Jeszcze tylko niespodzianka z kolejnością inicjalizacji. Odpowiednie ostrzeżenie w kompilatorze wytyka tę potencjalną pomyłkę.

#include <iostream>

struct Checker {
    Checker() {
        std::clog << "default constructor Checker\n";
    }
    Checker(int a): a{a} {
        std::clog << "int arg constructor Checker a = "
                  << a << '\n';
    }
    int getA() const {
        return a;
    }
private:
    int a;
};

struct MyClass {
    // Mimo innej kolejności w liście inicjalizacyjnej,
    // inicjalizacja przebiegnie w kolejności definicji atrybutów
    // w klasie czyli: checker1, checker2, checker3
    MyClass(int a): checker3{}, checker1{a}, checker2{12} {
    }
private:
    Checker checker1;
    Checker checker2;
    Checker checker3;
};

int main() {
    MyClass myClass{42};
}

I tu tylko należy uważać by inicjalizacja atrybutów nie była od siebie zależna bo zawsze wykonywana jest w kolejności definicji atrybutów.

Jak się da, inicjuj w liście. Jeśli się nie da/nie umiesz/niezręczna klasa, trzeba będzie to zrobić w konstruktorze wiedząc o koszcie lub... zmienić klasę która się temu nie poddaje :)

I tyle.. 

+1 głos
odpowiedź 8 maja 2018 przez kevin Mądrala (5,010 p.)
Ile w tym prawdy to nie wiem ale gdzieś kiedyś przeczytałem że przy tym zapisie operacje wykonują się szybciej ( jest bardziej zoptymalizowany ). I chyba nowy standard ale ręki nie dam sobie uciąć za to co napisałem.
+1 głos
odpowiedź 9 maja 2018 przez Patrycjerz Mędrzec (192,340 p.)
Drugi zapis umożliwia inicjalizację stałych składowych klasy, pierwszy nie, gdyż przypisanie wartości następuje wtedy po deklaracji, co przy stałych jest niedozwolone. Również wywołanie konstruktora niedomyślnego składowej jest wtedy niemożliwe, jak i konstruktora niedomyślnego klasy bazowej.

Tak na prawdę lepiej używać zawsze drugiego zapisu, po prostu jest czytelniejszy, widać, co jest składową, a co nie. Dodając wymienione wyżej zalety nie ma sensu używać "klasycznego" konstruktora.
0 głosów
odpowiedź 9 maja 2018 przez Bondrusiek Maniak (61,370 p.)

Witam,

w pierwszym sposobie występuje przypisanie zmiennych. W tym przypadku najpierw tworzony jest konstruktor z jakimiś losowymi wartościami val i next a dopiero potem są one przypisywane do wartości d oraz n. Jak można wywnioskować jest tu niepotrzebne marnowanie mocy obliczeniowej. Najpierw są do zmiennych przypisane losowe wartość a dopiero później wartości z argumentów konstruktora. 

W drugim przypadku wykorzystujesz listę inicjalizacyjną. W takim przypadku konstruktor jest tworzony od razu z wartościami z argumentu konstruktora tzn val równa się d a next jest n. Mniej operacji.Dodatkowo jeśli masz pola(zmienne) w klasie które mają modyfikator const bądź są referencyjne to musisz użyć drugiego sposobu tworzenie konstruktora.

komentarz 9 maja 2018 przez niezalogowany

w pierwszym sposobie występuje przypisanie zmiennych. W tym przypadku najpierw tworzony jest konstruktor z jakimiś losowymi wartościami val next a dopiero potem są one przypisywane do wartości oraz n. Jak można wywnioskować jest tu niepotrzebne marnowanie mocy obliczeniowej. Najpierw są do zmiennych przypisane losowe wartość a dopiero później wartości z argumentów konstruktora. 

W drugim przypadku wykorzystujesz listę inicjalizacyjną. W takim przypadku konstruktor jest tworzony od razu z wartościami z argumentu konstruktora tzn val równa się next jest n. Mniej operacji.

Nie sądzę 

komentarz 9 maja 2018 przez Wiciorny Ekspert (269,120 p.)

@Bondrusiek, worzony jest konstruktor z jakimiś losowymi wartościami val next 

co za totalna bzdura... po drugie jak " one są przypisywane do wartości d i n" :d chyba wartości d i n jak juz sa przypisywane do val i next.

Swoją drogą ...  Jak można wywnioskować jest tu niepotrzebne marnowanie mocy obliczeniowej. 

kolejna bzdura " niby coś wiesz, ale nie do końca" ... i mylisz pojęcia.  

0 głosów
odpowiedź 9 maja 2018 przez Wiciorny Ekspert (269,120 p.)
Nie ma "lepsze". - to jest kwestia w programowaniu bardzo sporna, bardziej tu brzmi który model jest efektywniejszy od strony pracy programu.

Lista inicjalizacyjna po prostu jest poprawniejsza i szybsza.

W drugim mówisz "zainicjuj te zmienne wartościami 3, 4, 5", w pierwszym  "zainicjuj je domyślnie... a wiesz co, potem im przypisz wartości 3, 4, 5."

Z czego w jak ktoś tu nieumyślnie próbował wyjaśnić: zauważ, że nakłada się ilość operacji dla przypadku pierwszego - a ilość operacji zwiększa time complexity, czyli czas programu  nakładając n* takich sytuacji na n * konstruktorów rośnie nam czas znacznie przez co efektywność programu spada.

Podobne pytania

+1 głos
2 odpowiedzi 630 wizyt
pytanie zadane 30 października 2015 w C i C++ przez macik1423 Początkujący (480 p.)
+1 głos
4 odpowiedzi 671 wizyt
pytanie zadane 17 czerwca 2016 w Java przez Daniel Dzwonkowski Nowicjusz (230 p.)
0 głosów
1 odpowiedź 463 wizyt
pytanie zadane 16 listopada 2022 w PHP przez zbiku25 Bywalec (2,940 p.)

92,453 zapytań

141,262 odpowiedzi

319,086 komentarzy

61,854 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Akademia Sekuraka 2024 zapewnia dostęp do minimum 15 szkoleń online z bezpieczeństwa IT oraz dostęp także do materiałów z edycji Sekurak Academy z roku 2023!

Przy zakupie możecie skorzystać z kodu: pasja-akademia - użyjcie go w koszyku, a uzyskacie rabat -30% na bilety w wersji "Standard"! Więcej informacji na temat akademii 2024 znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...