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

Dlaczego ten konstruktor jest lepszy?

Object Storage Arubacloud
0 głosów
349 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,320 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,710 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,710 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 633 wizyt
pytanie zadane 30 października 2015 w C i C++ przez macik1423 Początkujący (480 p.)
+1 głos
4 odpowiedzi 680 wizyt
pytanie zadane 17 czerwca 2016 w Java przez Daniel Dzwonkowski Nowicjusz (230 p.)
0 głosów
1 odpowiedź 507 wizyt
pytanie zadane 16 listopada 2022 w PHP przez zbiku25 Bywalec (2,940 p.)

92,551 zapytań

141,393 odpowiedzi

319,523 komentarzy

61,936 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

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy 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!

...