Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: fortran1986 21. 09. 2019, 15:59:52

Název: C++ no default constructor exists for class
Přispěvatel: fortran1986 21. 09. 2019, 15:59:52
Posledne 2 - 3 tyzdne som sa zacal zaujimat o C++, pretoze som pisal 1 projekt a jednu jeho cast by som asi najradsej napisal v C++.

Ten projekt isiel teraz bokom, lebo najprv sa ten jazyk musim poriadne naucit (aj keby to malo trvat roky), nakupil som si k nemu literaturu - 4 knihy. 2 hrube 2 tensie a postupne sa s tymto jazykom zoznamujem. Medzitym som zacal pisat jeden mensi projekt, taka utilitka aby som si v C++ nieco realne nakodil a vyskusal si moznosti jazyka a zistil kde vsade mam este medzery vo vedomostiach.

Ten jazyk ma dost chytil. Ale stale v nom mam pocit neistoty a obcas sa v duchu pytam WTF. Niektore konstrukcie v C++ sa mi zdaju ako z ineho sveta a v ziadnom inom jazyku som sa s takym niecim nestretol, ale na druhej strane ma bavi spoznavat nieco nove.

1. Teraz som napriklad narazil na jednu chybu a neviem co s nou  je na riadku 41 "no default constructor exists for class"

cast zdrojaka je tu: https://pastebin.com/M8vmiqiv

Vedeli by ste mi portadit ako to vyriesit?

2. Vedeli by ste mi pozret zdrojak ci niektore veci nerobim uplne zle? Pripustam ze tam mozem mat dost vazne logicke chyby, alebo mi tam mozu hrozit memory leaky holt som zaciatocnik. Napriklad na riadkoch 26, 27, 47, 48 sa robi kopia celeho vektoru hodnotou? nemal by som to skor riesit cez referenciu?

3. Tiez by ma zaujimalo ci existuje nejaky standard ktory by sa mal dodrziavat pri tvorbe nazvov identifikatorov. Lebo kazdy druhy zdrojak sa drzi niecoho ineho.
Název: Re:C++ no default constructor exists for class
Přispěvatel: ByCzech 21. 09. 2019, 16:17:24
Pro pochopení si přečtěte toto: https://stackoverflow.com/questions/4981241/no-default-constructor-exists-for-class a pak vytvořte správě default contructor pro třídu CustomSlot
Název: Re:C++ no default constructor exists for class
Přispěvatel: František Ryšánek 21. 09. 2019, 16:18:39
A takhle to vysvětluje Bruce Eckel (https://www.fi.muni.cz/usr/jkucera/tic/tic0078.html).
Název: Re:C++ no default constructor exists for class
Přispěvatel: Kit 21. 09. 2019, 18:25:06
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.
Název: Re:C++ no default constructor exists for class
Přispěvatel: František Ryšánek 21. 09. 2019, 19:32:13
Na tomhle serveru se pravidelně projevuje několik odborníků na jazyky a konkrétně C++. Já sám jsem hobbík a nedouk, dělám spíš do včel. A možná právě proto jsem na té správné úrovni, abych tady trochu něco okomentoval, ze své nevysoké pozorovatelny.

Takže po tomto disclaimeru ještě k bodům 2 a 3:


2.) jasně, návratovou hodnotou Vaší metody je vector, předávaný hodnotou. Inu proč ne :-) C++ to umí.

Osobně když tohle vidím, mám přirozený sklon říct "fuj, tohle se mělo předat odkazem". Ale ono ve skutečnosti záleží na situaci. V mnoha případech si řekněte "a zrovna ne, vždyť bych to o kus dál stejně musel kopírovat, a to nějak složitěji ručně/oklikou". A i kdyby to bylo trochu neefektivní... tak co? Záleží, jestli ta neefektivita něčemu vadí. Jestli si pomůžete v rovině "uživatelského dojmu", když místo předávky hodnotou předáte jenom referenci. Nebo napak v dané situaci (nějaký objektový model) je z hlediska fungování aplikace správně, předat odkaz, tzn. nikoli provádět hloubkovou kopii nějaké hierarchie instancí.

V obecnější rovině: C++ jakožto následník C má v genech takovou obecnou snahu, zamezit klasickým céčkovým nešvarům jako je opomenutí dealokace již nepotřebného objektu, nebo dereference pointeru na již dealokovaný objekt (nebo null pointeru) nebo opomenutí alokovaný objekt inicializovat na počáteční smysluplný stav apod. A snahou správců jazyka C++ vždy bylo, nabídnout základní primitiva a "programovací přístupy", která/které budou podobným situacím principielně předcházet. To že se do kontejnerů typu "vector" vkládají nejradši hodnoty (spíš než pointery nebo reference), to je přesně projev těchto snah. Nevím jestli má zásada "předávat hodnotou, nikoli odkazem" sama nějaké jméno, každopádně sousedí se zásadou RAII (1 (https://en.cppreference.com/w/cpp/language/raii), 2 (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)). Totiž pokud používáte objekty, které se RAII drží, a předáváte si je hodnotou, tak máte v C++ prakticky po starostech s "vlastnictvím", životním cyklem instance, automatickou alokací a dealokací.

Odkud to C++ vlastně studujete? Máte nějakou představu o Céčku, umíte používat jeho pointery, nabil jste si o ně párkrát nos? Nebo znáte klasickou práci s "dynamickými daty" a ukazateli v nějakém jiném jazyce téhle generace? (Packal?) Už jste narazil na C++ reference a jejich rozdíl oproti klasickým pointerům? (C++ Reference jsou další taková finta, jak sice nepředávat hodnotou, ale zároveň se za každou cenu vyhnout situaci, kdy reference bude naplatná.) A potkáte strong pointery... a já osobně (neživím se tím) teď jak trochu dohledávám další čtení okolo, narazil jsem na dvě (https://www.fluentcpp.com/2018/07/17/how-to-construct-c-objects-without-making-copies/) povídání (https://www.fluentcpp.com/2018/02/06/understanding-lvalues-rvalues-and-their-references/), ze kterých mi jdou oči trochu křížem... Prostě jsem spíš nenapravitelný céčkař.

Osobně jsem i jako hobbík už tu a tam napsal nějaký kus softwaru, kde trochu rozsáhlejší datový model znemožňoval, používat prosté předávání hodnotou. Zkrátka to nedávalo smysl. Objekty na heapu byly pěkně navzájem prolinkované odkazy (často nakonec prostými pointery, nebo strong pointery) a předávání hodnotou by bylo koncepčně blbě, protože by tím vznikla pokaždé další nová instance objektu, nová kopie.

Čili osobně si z toho beru tolik, že ty syntaktické nástroje, jak si "samotížně" zajistit RAII a vyhnout se mrtvým pointerům, jsou dobré na úplně spodní vrstvu, úplně nejdrobnější součástky, ze kterých stavíte svou katedrálu. Na trochu vyšších vrstvách skladebnosti už si musíte sám nést odpovědnost za "vlastnictví" objektů a jejich životní cyklus. C++ Vám k tomu bude maximálně nápomocno - takže se můžete soustředit na těch několik momentů, kdy objekt přechází např. ze stavu "základní prázdný zhruba inicializovaný" do "plně zabydlený" do "připojený a aktivní" apod., můžete se soustředit na správný moment, kdy (a v jakém pořadí) má instance objektu automaticky dealokovat vlastněné objekty (při graceful shutdownu), držené přes nějaký kontejner pointerů apod. Došel jsem zhruba k intruzivním šablonám pro autodestrukci na bázi reference countingu... (v kombinaci se strong pointers). A jsem si vědom, že to je pořád velice "lopatí" úroveň programovací černé magie.


3.) konvence tvorby jmen... osobně vím cca o dvou rozšířených variantách:
 
A) to co je vidět v Linuxu = všechna písmenka malá a mezi slovy podtržítka
B) "maďarská notace", dost rozšířená v Microsoftím světě
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.

Ona je to zřejmě podmnožina širšího "coding style". Obecně když přispíváte do nějakého projektu, měl byste se držet stávajícího stylu - vč. věcí jako kde dávat otvírací závorku bloku, kolik pevných mezer odpovídá tabulátoru apod.
Pokud začínáte na zelené louce svůj vlastní kousek softwaru, možná zvažte, ze kterého tábora bude převažující "odborné publikum".
Název: Re:C++ no default constructor exists for class
Přispěvatel: Kit 21. 09. 2019, 20:08:28
A) to co je vidět v Linuxu = všechna písmenka malá a mezi slovy podtržítka
B) "maďarská notace", dost rozšířená v Microsoftím světě
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.

Ad A) snake notace je OK.
Ad B) maďarské notace se zbavuje i Microsoft.
Ad C) tomu je třeba vyhnout se velkým obloukem.

Obecně by mělo platit, že "globálnější" proměnná by měla mít popisnější název než proměnná lokální. Řídicí proměnné cyklu mohou být klidně i jednoznakové i, j, k.
Název: Re:C++ no default constructor exists for class
Přispěvatel: Idris 21. 09. 2019, 21:02:17
Na tomhle serveru se pravidelně projevuje několik odborníků na jazyky a konkrétně C++. Já sám jsem hobbík a nedouk, dělám spíš do včel. A možná právě proto jsem na té správné úrovni, abych tady trochu něco okomentoval, ze své nevysoké pozorovatelny.

Takže po tomto disclaimeru ještě k bodům 2 a 3:


2.) jasně, návratovou hodnotou Vaší metody je vector, předávaný hodnotou. Inu proč ne :-) C++ to umí.

Osobně když tohle vidím, mám přirozený sklon říct "fuj, tohle se mělo předat odkazem". Ale ono ve skutečnosti záleží na situaci. V mnoha případech si řekněte "a zrovna ne, vždyť bych to o kus dál stejně musel kopírovat, a to nějak složitěji ručně/oklikou". A i kdyby to bylo trochu neefektivní... tak co? Záleží, jestli ta neefektivita něčemu vadí. Jestli si pomůžete v rovině "uživatelského dojmu", když místo předávky hodnotou předáte jenom referenci. Nebo napak v dané situaci (nějaký objektový model) je z hlediska fungování aplikace správně, předat odkaz, tzn. nikoli provádět hloubkovou kopii nějaké hierarchie instancí.

V obecnější rovině: C++ jakožto následník C má v genech takovou obecnou snahu, zamezit klasickým céčkovým nešvarům jako je opomenutí dealokace již nepotřebného objektu, nebo dereference pointeru na již dealokovaný objekt (nebo null pointeru) nebo opomenutí alokovaný objekt inicializovat na počáteční smysluplný stav apod. A snahou správců jazyka C++ vždy bylo, nabídnout základní primitiva a "programovací přístupy", která/které budou podobným situacím principielně předcházet. To že se do kontejnerů typu "vector" vkládají nejradši hodnoty (spíš než pointery nebo reference), to je přesně projev těchto snah. Nevím jestli má zásada "předávat hodnotou, nikoli odkazem" sama nějaké jméno, každopádně sousedí se zásadou RAII (1 (https://en.cppreference.com/w/cpp/language/raii), 2 (https://en.wikipedia.org/wiki/Resource_acquisition_is_initialization)). Totiž pokud používáte objekty, které se RAII drží, a předáváte si je hodnotou, tak máte v C++ prakticky po starostech s "vlastnictvím", životním cyklem instance, automatickou alokací a dealokací.

Odkud to C++ vlastně studujete? Máte nějakou představu o Céčku, umíte používat jeho pointery, nabil jste si o ně párkrát nos? Nebo znáte klasickou práci s "dynamickými daty" a ukazateli v nějakém jiném jazyce téhle generace? (Packal?) Už jste narazil na C++ reference a jejich rozdíl oproti klasickým pointerům? (C++ Reference jsou další taková finta, jak sice nepředávat hodnotou, ale zároveň se za každou cenu vyhnout situaci, kdy reference bude naplatná.) A potkáte strong pointery... a já osobně (neživím se tím) teď jak trochu dohledávám další čtení okolo, narazil jsem na dvě (https://www.fluentcpp.com/2018/07/17/how-to-construct-c-objects-without-making-copies/) povídání (https://www.fluentcpp.com/2018/02/06/understanding-lvalues-rvalues-and-their-references/), ze kterých mi jdou oči trochu křížem... Prostě jsem spíš nenapravitelný céčkař.

Osobně jsem i jako hobbík už tu a tam napsal nějaký kus softwaru, kde trochu rozsáhlejší datový model znemožňoval, používat prosté předávání hodnotou. Zkrátka to nedávalo smysl. Objekty na heapu byly pěkně navzájem prolinkované odkazy (často nakonec prostými pointery, nebo strong pointery) a předávání hodnotou by bylo koncepčně blbě, protože by tím vznikla pokaždé další nová instance objektu, nová kopie.

Čili osobně si z toho beru tolik, že ty syntaktické nástroje, jak si "samotížně" zajistit RAII a vyhnout se mrtvým pointerům, jsou dobré na úplně spodní vrstvu, úplně nejdrobnější součástky, ze kterých stavíte svou katedrálu. Na trochu vyšších vrstvách skladebnosti už si musíte sám nést odpovědnost za "vlastnictví" objektů a jejich životní cyklus. C++ Vám k tomu bude maximálně nápomocno - takže se můžete soustředit na těch několik momentů, kdy objekt přechází např. ze stavu "základní prázdný zhruba inicializovaný" do "plně zabydlený" do "připojený a aktivní" apod., můžete se soustředit na správný moment, kdy (a v jakém pořadí) má instance objektu automaticky dealokovat vlastněné objekty (při graceful shutdownu), držené přes nějaký kontejner pointerů apod. Došel jsem zhruba k intruzivním šablonám pro autodestrukci na bázi reference countingu... (v kombinaci se strong pointers). A jsem si vědom, že to je pořád velice "lopatí" úroveň programovací černé magie.


3.) konvence tvorby jmen... osobně vím cca o dvou rozšířených variantách:
 
A) to co je vidět v Linuxu = všechna písmenka malá a mezi slovy podtržítka
B) "maďarská notace", dost rozšířená v Microsoftím světě
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.

Ona je to zřejmě podmnožina širšího "coding style". Obecně když přispíváte do nějakého projektu, měl byste se držet stávajícího stylu - vč. věcí jako kde dávat otvírací závorku bloku, kolik pevných mezer odpovídá tabulátoru apod.
Pokud začínáte na zelené louce svůj vlastní kousek softwaru, možná zvažte, ze kterého tábora bude převažující "odborné publikum".
V C++ je “předání hodnotou” jen sémantika, při návratu z funkce může objekt klidně zůstat na zásobníku nebo se provede move (tedy bez kopírování vnitřností).
Název: Re:C++ no default constructor exists for class
Přispěvatel: Cikáda 21. 09. 2019, 23:31:28
Výborný zdroj na C++ je https://en.cppreference.com.

3.) konvence tvorby jmen... osobně vím cca o dvou rozšířených variantách:
 
A) to co je vidět v Linuxu = všechna písmenka malá a mezi slovy podtržítka
B) "maďarská notace", dost rozšířená v Microsoftím světě
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.

Tak hlavně je buď snake_case notace
Kód: [Vybrat]
my_number, nebo camelCase
Kód: [Vybrat]
myNumber.
Nejdůležitější je pojmenovávat tak, aby bylo co nejjasnější, o co jde a také, aby ten styl byl jednotný.

( C) je samozřejmě blbost s Perlem nesouvisející, je rozdíl mezi built-in/idiomatickými proměnnými a tím, jak se pojmenovávají "uživatelské" proměnné.)
Název: Re:C++ no default constructor exists for class
Přispěvatel: Wavelet 22. 09. 2019, 12:49:53
Ahoj, zkus použít "constructor initialization list".  Přecházíš ze C# nebo Javy?

Kód: [Vybrat]
   
class CustomSlot
...
    public:
        CustomSlot(
            const unsigned int index,
            const KeyboardShortcut copy_shortcut,
            const KeyboardShortcut paste_shortcut
        )
            :_index(index),
            _copy_shortcut(copy_shortcut),
            _paste_shortcut(paste_shortcut)
        {}
...
};
Název: Re:C++ no default constructor exists for class
Přispěvatel: Wavelet 22. 09. 2019, 13:04:51
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP? Bonus: https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=24&cad=rja&uact=8&ved=2ahUKEwjm0JGqo-TkAhXFCewKHT-2CW8QFjAXegQIBBAC&url=http%3A%2F%2Fwww.stroustrup.com%2Foopsla.pdf&usg=AOvVaw0GZ9o3j-mGGsNO9vXy9Etl;
Název: Re:C++ no default constructor exists for class
Přispěvatel: Kit 22. 09. 2019, 14:22:37
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP?

V tom případě může rovnou použít struct nebo třídu s veřejnými atributy (resp. read-only) a vyjde to nastejno - spíš lépe.
Název: Re:C++ no default constructor exists for class
Přispěvatel: fortran1986 22. 09. 2019, 14:25:49

Dakujem ti za informáciami nabitý príspevok a sumár tvojich skúseností ale k tvojim otázkam: ja sa učím hlavne z kníh mám ich dosť veľa a keď niečomu nerozumiem tak si o tom prečítam celú kapitolu rad - radom vo všetkých štyroch, ale v tomto konkrétnom prípade (inicializacia objektu vnoreného membera) som sa k tomu ešte nedostal.

Tvoj post som si viac krát prečítal a aj si ho archivujem (ak dovolíš). Jo a s pointermi mám skúsenosti ešte s delphi a pascalu pamatám si že som ich tam občas používal hlavne pri práci s grafikou. A teraz som sa s nimi dostal do kontaktu aj v .NETe (v unsafe) C# má pointerovú aritmetiku skoro na takej úrovni ako C++ aj keď v C++ je to stále ešte o chlp lepšie a preto som sa rozhodol že jednu časť appky prepíšem z .NETu do natívnej podoby.

Ahoj, zkus použít "constructor initialization list".  Přecházíš ze C# nebo Javy?

Prechádzam z viacerých jazykov (C#, F#, JS, TS, PHP) všetky majú triedy na jedno kopyto, a nikde som sa nestretol s tým aby som takýmto spôsobom musel inicializovať aj vnoreného membera, vždy sa to takto robilo iba pri predkoch. A rád by som počul vysvetlenie prečo je to nutné aj pri vnorených objektoch.
Název: Re:C++ no default constructor exists for class
Přispěvatel: fortran1986 22. 09. 2019, 14:27:40
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP?

V tom případě může rovnou použít struct nebo třídu s veřejnými atributy (resp. read-only) a vyjde to nastejno - spíš lépe.

Ale potom nebude immutable. Snažil som sa naemulovať immutable štruktúru ktorá sa dá len čítať. Okrem toho ja ako funkcionálny programátor nemám nič proti anemickým objektom.
Název: Re:C++ no default constructor exists for class
Přispěvatel: Wavelet 22. 09. 2019, 14:43:57
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP?

V tom případě může rovnou použít struct nebo třídu s veřejnými atributy (resp. read-only) a vyjde to nastejno - spíš lépe.

Ale potom nebude immutable. Snažil som sa naemulovať immutable štruktúru ktorá sa dá len čítať. Okrem toho ja ako funkcionálny programátor nemám nič proti anemickým objektom.

Přidej si k privátním proměnným `const`.
A dál citace: "Basically when data members are declared constant they have to have some value before the object is constructed Hence we use member initializer so that before the object is constructed the data member has some value."

https://en.cppreference.com/w/cpp/language/initializer_list
https://www.learncpp.com/cpp-tutorial/8-5a-constructor-member-initializer-lists/

Pokud jsou to *immutable value objects*, tak ti chybí minimálně implementace `==`, `!=` a `std::hash`.
Název: Re:C++ no default constructor exists for class
Přispěvatel: Kit 22. 09. 2019, 15:00:29
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP?

V tom případě může rovnou použít struct nebo třídu s veřejnými atributy (resp. read-only) a vyjde to nastejno - spíš lépe.

Ale potom nebude immutable. Snažil som sa naemulovať immutable štruktúru ktorá sa dá len čítať. Okrem toho ja ako funkcionálny programátor nemám nič proti anemickým objektom.

Immutable je něco jiného než read-only?
Název: Re:C++ no default constructor exists for class
Přispěvatel: Idris 22. 09. 2019, 15:30:45
Ta třída má jednu zásadní vadu: Nic neumí. Vyvaruj se tvorby takových anemických tříd, dej do nich alespoň jednu metodu.

Kromě toho, že to je ukázkový příklad, tak třída  (struktura) v C++ nemusí nic "umět". C++ není OO jazyk (ala C#/Java), klidně se dá pracovat se strukturama a volnýma funkcema ... nakonec popírá to OOP?

V tom případě může rovnou použít struct nebo třídu s veřejnými atributy (resp. read-only) a vyjde to nastejno - spíš lépe.

Ale potom nebude immutable. Snažil som sa naemulovať immutable štruktúru ktorá sa dá len čítať. Okrem toho ja ako funkcionálny programátor nemám nič proti anemickým objektom.

Immutable je něco jiného než read-only?
Ano.
Název: Re:C++ no default constructor exists for class
Přispěvatel: František Ryšánek 22. 09. 2019, 22:01:06
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.
...
( C) je samozřejmě blbost s Perlem nesouvisející, je rozdíl mezi built-in/idiomatickými proměnnými a tím, jak se pojmenovávají "uživatelské" proměnné.)
[/quote]

O nic nejde - nejsem si jist jestli si správně rozumíme, pro jistotu upřesním: měl jsem na mysli Céčkové zdrojáky samotného Perl interpretru, viz např. datový typ SV znamená Scalar Value, třeba tady (https://perl5.git.perl.org/perl.git/blob/HEAD:/sv.c) na řádku 321 atd. (deklarace 'SV* sv;' a návazná užití té proměnné). Celá perlová střeva (https://perldoc.perl.org/perlguts.html#Datatypes) jsou špikována takto pojmenovanými elementárními typy. Připomíná to písničku "Zkratky" od Ivana Mládka.
Název: Re:C++ no default constructor exists for class
Přispěvatel: František Ryšánek 22. 09. 2019, 23:13:54
Prechádzam z viacerých jazykov (C#, F#, JS, TS, PHP) všetky majú triedy na jedno kopyto, a nikde som sa nestretol s tým aby som takýmto spôsobom musel inicializovať aj vnoreného membera, vždy sa to takto robilo iba pri predkoch. A rád by som počul vysvetlenie prečo je to nutné aj pri vnorených objektoch.

...je možné, že jsem nepochopil správně otázku, protože o zmíněných jazycích toho vím málo. Zjevně postupujete od jazyků vyšší úrovně dolů, směrem ke "kvalitnímu assembleru" :-)

Tedy "proč povinně inicializovat vnořené membery" : soudím, že se jedná o základní projev zásady RAII. Rodí se instance objektu, a v okamžiku zrodu je třeba ji uvést do nějakého smysluplného/konzistentního počátečního stavu. Tzn. dát nějaký smysluplný počáteční stav všem obsaženým memberům. Třeba je všecky jenom vynulovat - ale prostě jasně definovaný stav, na který se následně můžete spolehnout. Spolu se to alokuje, tak se to má spolu taky inicializovat.
Osobně jsem se několikrát dostal do situace, kdy nebylo možné implementovat nějaké další inicializační kroky v konstruktoru. To je v pořádku, další životní oblouk či stavový mechanismus právě vzniklé instance je už Vaše odpovědnost.
Buď se dá objekt na této nízké úrovni inicializovat v konstruktoru na hodnoty "já jsem zatím jenom prázdná skořápka". Nebo se třeba problematičtí "membeři", ke kterým zatím nemáte co říct, dají vyčlenit do samostatných objektů, na které se odkážete pointerem (nebo možná C++ referencí, nebo odkazy na ně zabalíte do nějakého kontejneru, který může mít do začátku nulový počet prvků apod.) - takové "externě odkázané membery" pak nemusíte inicializovat současně s "držitelskou instancí"... čímž ovšem za ně pochopitelně přebíráte odpovědnost.
Pokud jsem otázku nepochopil, tak se omlouvám :-)

Zmínil jste, že v jiných jazycích se povinně inicializují jenom "věci zděděné od předka", nikoli vlastní membeři. Což mi off topic připomnělo kapitolu od Bruce Eckela zvanou Inheritance and Composition (https://www.fi.muni.cz/usr/jkucera/tic/tic0142.html) (možná lépe najít v obsahu kap.č.14 (https://www.fi.muni.cz/usr/jkucera/tic/tic_c.html))
Název: Re:C++ no default constructor exists for class
Přispěvatel: Cikáda 23. 09. 2019, 15:10:18
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.
...
( C) je samozřejmě blbost s Perlem nesouvisející, je rozdíl mezi built-in/idiomatickými proměnnými a tím, jak se pojmenovávají "uživatelské" proměnné.)

O nic nejde - nejsem si jist jestli si správně rozumíme, pro jistotu upřesním: měl jsem na mysli Céčkové zdrojáky samotného Perl interpretru, viz např. datový typ SV znamená Scalar Value, třeba tady (https://perl5.git.perl.org/perl.git/blob/HEAD:/sv.c) na řádku 321 atd. (deklarace 'SV* sv;' a návazná užití té proměnné). Celá perlová střeva (https://perldoc.perl.org/perlguts.html#Datatypes) jsou špikována takto pojmenovanými elementárními typy. Připomíná to písničku "Zkratky" od Ivana Mládka.

Tak to se omlouvám, opravdu jsem to pochopil špatně.
I když si stále nemyslím, že by to měl být nějaký "standalone" styl pojmenovávání proměnných, spíš prostě způsob jak si ulehčit psaní dlouhých jmen, když je to v tu chvíli jasné.
Název: Re:C++ no default constructor exists for class
Přispěvatel: Kit 23. 09. 2019, 16:40:14
C) občas je k vidění varianta "maximálně úsporná" = jména symbolů jsou 2-4 znaky dlouhé zkratky :-) Viz třeba zdrojáky Perlu.
...
( C) je samozřejmě blbost s Perlem nesouvisející, je rozdíl mezi built-in/idiomatickými proměnnými a tím, jak se pojmenovávají "uživatelské" proměnné.)

O nic nejde - nejsem si jist jestli si správně rozumíme, pro jistotu upřesním: měl jsem na mysli Céčkové zdrojáky samotného Perl interpretru, viz např. datový typ SV znamená Scalar Value, třeba tady (https://perl5.git.perl.org/perl.git/blob/HEAD:/sv.c) na řádku 321 atd. (deklarace 'SV* sv;' a návazná užití té proměnné). Celá perlová střeva (https://perldoc.perl.org/perlguts.html#Datatypes) jsou špikována takto pojmenovanými elementárními typy. Připomíná to písničku "Zkratky" od Ivana Mládka.

Tak to se omlouvám, opravdu jsem to pochopil špatně.
I když si stále nemyslím, že by to měl být nějaký "standalone" styl pojmenovávání proměnných, spíš prostě způsob jak si ulehčit psaní dlouhých jmen, když je to v tu chvíli jasné.

Ono by to bylo špatně i v případě, kdyby se ta proměnná jmenovala scalar_value.
Název: Re:C++ no default constructor exists for class
Přispěvatel: fortran1986 25. 09. 2019, 22:46:04
Ďakujem Vám všetkým a hlavne Františkovi (ale aj ostatným).

Ospravedlňujem sa že som skôr nereagoval ale kým o tom nemám dostatok informácií tak nechcem vyzerať ako úplný analfabet. Už začínam chápať kde bol problém preto sa teraz študujem pointery a referencie aby som mal istotu čo kedy a kde použiť (A hlavne sa hráme s shared_ptr a unique_ptr) Teda viem ako tie pointery fungujú ale dosť často napriek tomu tápem či mám ten objekt alokovať na stacku alebo heape.
Název: Re:C++ no default constructor exists for class
Přispěvatel: registrovany_ava 26. 09. 2019, 20:32:58
Ďakujem Vám všetkým a hlavne Františkovi (ale aj ostatným).

Ospravedlňujem sa že som skôr nereagoval ale kým o tom nemám dostatok informácií tak nechcem vyzerať ako úplný analfabet. Už začínam chápať kde bol problém preto sa teraz študujem pointery a referencie aby som mal istotu čo kedy a kde použiť (A hlavne sa hráme s shared_ptr a unique_ptr) Teda viem ako tie pointery fungujú ale dosť často napriek tomu tápem či mám ten objekt alokovať na stacku alebo heape.

Hmm, možná už je pozdě, ale neuvažoval jsi, že by ses místo C++ začal učit Rust? Jestli to máš na vlastní projekty, myslím, že by se ti mohl líbit víc, obzvlášť pokud píšeš že jsi programoval funkcionálně tě oproti C++ potěší ADT přímo v jazyce, absence NULL a výjimek, nemožnost data races nebo neplatného přístupu do paměti (double free, use after free, leaky).. Cílová skupina je asi ta samá, systémové programování. Ale jestli to hledáš kvůli komerčnímu uplatnění, tak toho je v C++ samozřejmě víc..
Název: Re:C++ no default constructor exists for class
Přispěvatel: František Ryšánek 27. 09. 2019, 00:15:42
Na stacku vs. na heapu:

A) Lokální proměnné uvnitř funkce (včetně argumentů deklarovaných v prototypu) se házejí na stack. V user space v moderním OS asi není problém, že by na stacku nebylo dost místa - ale je třeba si uvědomit, že věci na stacku mají omezenou životnost. Jakmile skončí dotyčná funkce, její lokální proměnné se vypaří (out of scope), tzn. stack pointer se vrátí o jeden stack frame výš (stack tradičně roste směrem dolů). Pokud jsou lokálně deklarované nějaké skutečné objekty, proběhne v rámci ukončení funkce jejich destruktor.

B) Instance vytvořené operátorem "new" jsou alokovány na heapu. Na takovou novou instanci dostanete pointer. Pokud takový pointer máte deklarovaný jako lokální proměnnou ve funkci (běžná situace) tak samotný pointer samozřejmě skončí s touto funkcí, ale odkazovaná instance na heapu žije dál. Pokud by Vás to téma zajímalo, tak C++ sice nemá garbage collector, ale alokaci různě velkých věcí na heapu řídí tzv. allocator. Přiděluje a uvolňuje místo, vede si přehled o jednotlivých alokacích, snaží se bránit fragmentaci (ve spolupráci s memory managementem OS = záleží i na podvozku).

C) Popravdě mi není z hlavy úplně jasné, kde jsou alokovány proměnné/objekty, deklarované jako globální v konkrétním Cčkovém souboru (translation unit). Patrně se stanou součástí spustitelného binárního souboru (nebo knihovny) a mají tím alokované místo. Tzn. představte si takový objekt jako "bublinu" uvnitř nějakého toho ELF nebo PE-COFF bináru - do RAMky se dostane zavedením toho bináru ke spuštění. Jisté je, že životnost těchto globálně deklarovaných objektů je shodná se životností běžícího executable bináru - pouze se při startu na to před-alokované místo poštve konstruktor a při ukončení destruktor.


Pak jste psal, že si hrajete se strong pointery... schválně zkusím přihodit střípek své naivní tvorby. "Manuálně invazivní" reference counting šablonu a k ní komplementární "chytrý pointer" (taky šablona). Vytvoříte pointer na nějakou svoji instanci obsahující tohoto refcounting parazita, a parazit ví, že na něj někdo odkazuje. Takových pointerů může být víc. Pokud ten smart pointer projde destrukcí, refcount v odkazované instanci se automaticky sníží. Pokud spadne refcount na nulu, proběhne autodestrukce hostitelské instance refcounting parazitem. Pokud byste chtěl nesmrtelnou instanci, buď si naalokujte navrch jeden smart pointer, který nikdy nezničíte, nebo tu referenci prostě explicitně inkrementujte... (Ano, hrozně rád vynalézám kolo.)


Jojo. První krůčky s C++.

Mně osobně se v začátcích hodně líbila klasická poučka, že abstraktní třída musí mít čistě virtuální destruktor, ale musí pro něj mít definované tělo :-) Nebo jak to vlastně bylo... V původní podobě jsem tu poučku našel tady (https://www.geeksforgeeks.org/pure-virtual-destructor-c/). Nicméně už Bruce Eckel ve druhém vydání Thinking in C++ tvrdí, že tahle praxe je překonaná (https://www.fi.muni.cz/usr/jkucera/tic/tic0163.html), že dle novějšího standardu má být ten destruktor prostě jenom virtuální (s definovaným tělem = tohle platí dál).

Pak se dá dostat do situací, kde bojujete se zacyklenými deklaracemi tříd. Dalo by se ještě pochopit, že pokud B je memberem A, nelze zároveň deklarovat že A je memberem B. Nekonečná rekurzivita vnoření se nekoná. Ale do podobných lapálií se můžete dostat při použití šablonových tříd (https://stackoverflow.com/questions/3353831/resolving-a-circular-dependency-between-template-classes). Situaci nepomáhá, že šablony prakticky komplet žijí v hlavičkových souborech, takže nelze použít fintu "v hlavičkách se to jenom nadeklaruje a pak v těle (souboru CPP) se dořeší zbytky". Tuším jsem se asi dvakrát dostal do kouta, ze kterého jsem nenašel jinou cestu, než obalit jednu ze tříd do memberu typu void* :-)

Prostě zažívám okamžiky C++ WAT (https://www.youtube.com/watch?v=rNNnPrMHsAA) :-)

Popravdě mi šly oči trochu křížem z tohoto řádku ve Vašem zdrojáku:
  typedef function<void(KeyboardShortcut)> KeyboardCallback;
...ale nakonec pokud správně chápu, nejedná se o nic jiného než v Céčkové tradiční notaci (https://stackoverflow.com/questions/4295432/typedef-function-pointer)
  typedef void (*KeyboardCallback)(KeyboardShortcut);
...čili žádné velké funkcionální utrpení :-)
Já jsem totiž krajně procedurální tvor...