Lifetime static/global/heap-allocated objektu v C++

anonacct

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #15 kdy: 02. 08. 2022, 12:19:08 »
Spíš jde o to tu proměnnou "lazy" zinicializovat až když je opravdu potřeba, statická inicializace v C++ je tak trochu nepředvídatelná a spoláhat se na ni je cesta do pekel - proto bych vyhodil všechny globals a měl jen jeden - nějaký DI context nebo aplikační kontext, atd... popřípadě nemít ani ten a předávat ten kontext. Asi záleží na tom jak je kód na kterém tazatel děla starý - obvykle starší code-base má hodně globálních proměnných a něco s tím udělat by bylo na roky práce...


Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #16 kdy: 02. 08. 2022, 13:30:56 »
Ja vedel ze C++ je slepa cesta :) jen si hezky onanujte, vy uber-programatori.

Na vse ostatni staci takovy jednodychy on-demand generator:

Citace
typ *single() {
  static typ *instance;
  if (!instance) instance = &new typ();
  return instance;
}

To céčku je naozaj nutné kontrolovať, či statická premenná vo funkcii bola inicializovaná?

V C++ nie je, jednoducho to prebehne iba pri prvom volaní a platí to aj pre tú alokáciu pamäte.

A od C+11 je to aj thread-safe...
Pokud je ta statická proměnná ukazatel na dynamicky alokovaný objekt, tak je to nutné kontrolovat. V C++11 je thread safe tahle verze :
Citace
typ *single() {
  static typ instance;
  return &instance;
}
Protože thread safe je jen ta samotná inicializace statické proměnné.

Spíš jde o to tu proměnnou "lazy" zinicializovat až když je opravdu potřeba, statická inicializace v C++ je tak trochu nepředvídatelná a spoláhat se na ni je cesta do pekel - proto bych vyhodil všechny globals a měl jen jeden - nějaký DI context nebo aplikační kontext, atd... popřípadě nemít ani ten a předávat ten kontext. Asi záleží na tom jak je kód na kterém tazatel děla starý - obvykle starší code-base má hodně globálních proměnných a něco s tím udělat by bylo na roky práce...
Globální proměnné jsou problematické, ale statická proměnná uvnitř funkce je v pohodě. Ta se zinicializuje ve chvíli, kdy se ta funkce poprvé zavolá.

RDa

  • *****
  • 2 785
    • Zobrazit profil
    • E-mail
Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #17 kdy: 02. 08. 2022, 13:34:54 »
Mimochodem, ten jednoduchý on demand generátor na všechno rozhodně nestačí. Minimálně proto, že není thread-safe. A tazatel se ptal na thready, takže mu to nejspíš vadit bude.

Jiste ze to neni thread safe, protoze prirazeni ani { } si takovou extra namahu nedava.

To céčku je naozaj nutné kontrolovať, či statická premenná vo funkcii bola inicializovaná?
V C++ nie je, jednoducho to prebehne iba pri prvom volaní a platí to aj pre tú alokáciu pamäte.
A od C+11 je to aj thread-safe...

Pokud pisu zdrojak, pisu ho tak, abych nemusel poskytovat out-of-band informaci, jakou verzi standardu se na to ma prekladac divat.

U C++11 musite ale pouzit safe:: nebo tam plati nejake magicke pravidlo / vyjimka na kod podobny memu?

Nez jsem dopsal prispevek, tak se to zodpovedelo..

Pokud je ta statická proměnná ukazatel na dynamicky alokovaný objekt, tak je to nutné kontrolovat. V C++11 je thread safe tahle verze :
Citace
typ *single() {
  static typ instance;
  return &instance;
}
Protože thread safe je jen ta samotná inicializace statické proměnné.


anonacct

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #18 kdy: 02. 08. 2022, 15:07:59 »
Citace
Globální proměnné jsou problematické, ale statická proměnná uvnitř funkce je v pohodě. Ta se zinicializuje ve chvíli, kdy se ta funkce poprvé zavolá.

Jo, a kdy se zničí ta statická proměnná? Jediná možnost v tomto případě je udělat leak a alokovat ji na heapu a nikdy ji nezničit (takže mít static pointer).

Jinak thread safe inicialization má compile flag - pokud někdo kompiluje bez tak tyto hrátky se statickýma proměnnýma nejsou ani thread safe.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #19 kdy: 02. 08. 2022, 15:09:41 »
Pokud pisu zdrojak, pisu ho tak, abych nemusel poskytovat out-of-band informaci, jakou verzi standardu se na to ma prekladac divat.
Mám to chápat tak, že píšete v c++98 abyste ke všem těm out-of-band informacím jako jsou cesty ke knihovnám, úrovně optimalizací a další nastavení prostředí nemusel přidat jeden další parametr?

Všiml jste si, že všechny běžně používané jazyky přicházejí s novýma verzema, kde se (obvykle úspěšně) snaží programátorům ulehčit práci? A každý příčetný programátor tu out-of-band informaci rád poskytne aby nemusel používat prehistorickou verzi 0.666 z hlubin pekelných, pokud to není nezbytně nutné. :D


RDa

  • *****
  • 2 785
    • Zobrazit profil
    • E-mail
Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #20 kdy: 02. 08. 2022, 15:19:21 »
Všiml jste si, že všechny běžně používané jazyky přicházejí s novýma verzema, kde se (obvykle úspěšně) snaží programátorům ulehčit práci? A každý příčetný programátor tu out-of-band informaci rád poskytne aby nemusel používat prehistorickou verzi 0.666 z hlubin pekelných, pokud to není nezbytně nutné. :D

To mate jako se zavorkama a prioritama operatoru.. pridavam je i na mista kam bych nemusel, jen abych nemrhal mozkovymi cykly nad premyslenim co se provede driv. Asi mam v oblibe primitivni jistoty?

A v mem kodu taky najdete samostatne stojici bloky mezi { }, aniz by pred tim byla podminka - a kdyz uz je, je to vetsinou neco jako if (1), casteji tam ale byva comment pro celou grupu. Pro stroj je to zbytecny.. ale pro nas je tato moznost darem. Ne vzdy je nejkompaktnejsi zdrojak ten nejlepsi - hranici optimalna ale muzeme mit samozrejme jinde.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #21 kdy: 02. 08. 2022, 15:23:59 »
Citace
Globální proměnné jsou problematické, ale statická proměnná uvnitř funkce je v pohodě. Ta se zinicializuje ve chvíli, kdy se ta funkce poprvé zavolá.

Jo, a kdy se zničí ta statická proměnná? Jediná možnost v tomto případě je udělat leak a alokovat ji na heapu a nikdy ji nezničit (takže mít static pointer).
Statické proměnné se ničí při ukončování programu a to v opačném pořadí než vznikly. Trochu jako by se hned po tom vytvoření zavolal atexit.
Takže abyste se na tu proměnnou dostal po jejím zničení, musel byste na ni lézt z nějakého objektu, který existoval už předtím. To je poměrně obskurní použití, takže to moc nehrozí. Pokud nějaký sigleton potřebuje jiné singletony, pak stačí aby si o ně řekl už v konstruktoru a je za vodou.
Všechny implementace singletonů mají své pasti a tahle je na tom ještě docela v pohodě.
Citace
Jinak thread safe inicialization má compile flag - pokud někdo kompiluje bez tak tyto hrátky se statickýma proměnnýma nejsou ani thread safe.
Přes compile flagy se dá nastavit spousta dalších věcí - výjimky, RTTI, přesnost floatů, ... Pokud někdo vrtá do tohohle, tak holt musí vědět moc dobře, co dělá.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #22 kdy: 02. 08. 2022, 15:44:48 »
Všiml jste si, že všechny běžně používané jazyky přicházejí s novýma verzema, kde se (obvykle úspěšně) snaží programátorům ulehčit práci? A každý příčetný programátor tu out-of-band informaci rád poskytne aby nemusel používat prehistorickou verzi 0.666 z hlubin pekelných, pokud to není nezbytně nutné. :D

To mate jako se zavorkama a prioritama operatoru.. pridavam je i na mista kam bych nemusel, jen abych nemrhal mozkovymi cykly nad premyslenim co se provede driv. Asi mam v oblibe primitivni jistoty?

A v mem kodu taky najdete samostatne stojici bloky mezi { }, aniz by pred tim byla podminka - a kdyz uz je, je to vetsinou neco jako if (1), casteji tam ale byva comment pro celou grupu. Pro stroj je to zbytecny.. ale pro nas je tato moznost darem. Ne vzdy je nejkompaktnejsi zdrojak ten nejlepsi - hranici optimalna ale muzeme mit samozrejme jinde.
Tohle ale můžete dělat i v těch nových verzích. Ulehčením práce jsem opravdu nemyslel co nejkratší kód, ale právě kód kde se můžu soustředit na to důležité. A nové verze c++ imo přinesly pěkných pár věcí, co se chovají daleko příčetněji než starý binec.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #23 kdy: 02. 08. 2022, 17:36:55 »
Dekuji vsem za odpovedi.

Par poznamek:

1) Kdyby bylo po mem, staticky (tj. na stacku) bych naalokoval vse v mainu, predaval referenci v konstruktoru (umoznuje dependency injection) a zajistil graceful shutdown. Po mem ale bohuzel neni, ponevadz manazer lpi na globalni promenne (kvuli egu a protoze C++ nerozumi). Ja bych delal spoustu veci jinak.

2) Inicializace statickych, block-scoped promennych je skutecne thread-safe. Vygooglete si nasledujici vetu v C++ standardu:
Kód: [Vybrat]
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initializationTenhle singleton taktez nese jmeno Scotta Meyerse: https://laristra.github.io/flecsi/src/developer-guide/patterns/meyers_singleton.html. Soudim tedy, ze je to safe.

3) Rozumim-li spravne postu o kompilacnim flagu, pak je to nejspis toto:
Kód: [Vybrat]
-fno-threadsafe-statics
Do not emit the extra code to use the routines specified in the C++ ABI for thread-safe initialization of local statics. You can use this option to reduce code size slightly in code that doesn’t need to be thread-safe.
Z toho mi plyne, ze tento flag vypina thread-safety, tudiz defaultne je to safe.

Ale abych se vratil k otazce.

Trochu to prezenu, abych zduraznil absurditu :) Je mozne pristoupit k objektu na heap po korektnim zniceni cele heap v bezicim procesu? Tj. dobehnou vlakna, znici se heap a TED je ten okamzik :) Muze v tomto bode jeste napriklad bezet detached vlakno?

Lze to same udelat s korektne - na konci programu - dealokovanou statickou promennou?

Pokud nikoliv, vubec neni potreba tridu Sluzby dynamicky alokovat a uz vubec managovat ji nebo jeji membery pomoci std::shared_ptr.

A sem se snazim celou dobu dostat. Respektive, chci vedet, jestli neco neopomijim.

tecka

  • ***
  • 160
    • Zobrazit profil
    • E-mail
Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #24 kdy: 03. 08. 2022, 07:53:09 »
Ale alex nepsal o žádné globální instanci. V tom jeho příkladu byl "globální" akorát couter na základě kterého mohl ten nesingleton poznat, že je první. K těm samotným objektům na stacku žádný globální přístup nebyl.
Singletony se dělají tak, že vytvářím jen jednu instanci a ne, že namatlám třídu, která nedovolí víc než jednu instanci. Nebo si je dokonce počítá a u jiných než první se rozhodne nefungovat.

Jestli v jednom člověku píšete a testujete helloworldy, tak si klidně hrajte s nesmysly, co jste se minulý týden naučili ve škole, ale nechoďte s tím mezi lidi.
« Poslední změna: 03. 08. 2022, 07:55:24 od tecka »

tecka

  • ***
  • 160
    • Zobrazit profil
    • E-mail
Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #25 kdy: 03. 08. 2022, 07:54:17 »
Ma nejaky smysl, aby objekty uvnitr (Http klient a DB databaze) byly std::shared_ptr a ne proste staticky alokovane membery nebo alespon std::unique_ptr?

Chce se po mne, abych predaval vsechny reference na Http a DB pomoci kopirovani shared pointeru kvuli tomu, aby "nahodou" napr Http nebyl automaticky dealokovan drive nez ho neco pouzije.
Má to přesně ten smysl uvedený v dalším odstavci. Zadavatel/nadřízený si nejspíš uvědomuje, že kód má tendeci se vyvíjet a měnit, ten pointer nemusí být navždy unikátní a raw-pointer dříve nebo později někdo dokope. Nezáleží na tom, že zrovna teď zrovna v tomhle případě není nutný. Ničemu nevadí a předchází problému. Když se to po tobě takhle chce, tak to takhle udělej.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #26 kdy: 03. 08. 2022, 08:51:09 »
Ale abych se vratil k otazce.

Trochu to prezenu, abych zduraznil absurditu :) Je mozne pristoupit k objektu na heap po korektnim zniceni cele heap v bezicim procesu? Tj. dobehnou vlakna, znici se heap a TED je ten okamzik :) Muze v tomto bode jeste napriklad bezet detached vlakno?
Jo, zničit heap v běžícím procesu samozřejmě jde. Ale já teda nepotkal platformu, kde by se při ukončování likvidoval normální heap. Vždycky to zůstalo viset a tu paměť pak poklidil OS. Spousta programů nechává viset objekty, které nepotřebujou volat destruktory. Takže příčetné runtimy se úklidem heapu na konci neobtěžují. Akorát Valgrind a spol. v takovém případě kvičí.
Citace
Pokud nikoliv, vubec neni potreba tridu Sluzby dynamicky alokovat a uz vubec managovat ji nebo jeji membery pomoci std::shared_ptr.
Jedna motivace může být i variace na PIMPL. Pokud uživatelé té Sluzby nepotřebují vždycky všechno, tak nemusí includovat potenciálně dost veliké headery s hromadou symbolů ale pro nepoužité věci jim stačí forward deklarace. U velikého projektu to může být zajímavá úspora nejen času kompilace ale i místa na disku pro objektové soubory.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #27 kdy: 03. 08. 2022, 13:09:32 »
Ma nejaky smysl, aby objekty uvnitr (Http klient a DB databaze) byly std::shared_ptr a ne proste staticky alokovane membery nebo alespon std::unique_ptr?

Chce se po mne, abych predaval vsechny reference na Http a DB pomoci kopirovani shared pointeru kvuli tomu, aby "nahodou" napr Http nebyl automaticky dealokovan drive nez ho neco pouzije.
Má to přesně ten smysl uvedený v dalším odstavci. Zadavatel/nadřízený si nejspíš uvědomuje, že kód má tendeci se vyvíjet a měnit, ten pointer nemusí být navždy unikátní a raw-pointer dříve nebo později někdo dokope. Nezáleží na tom, že zrovna teď zrovna v tomhle případě není nutný. Ničemu nevadí a předchází problému. Když se to po tobě takhle chce, tak to takhle udělej.

Slysel jste nekdy o YAGNI? A kdybych mel vzdycky delat jen to, co se po mne chce, asi bych byl porad jeste junior... :)

Ale abych se vratil k otazce.

Trochu to prezenu, abych zduraznil absurditu :) Je mozne pristoupit k objektu na heap po korektnim zniceni cele heap v bezicim procesu? Tj. dobehnou vlakna, znici se heap a TED je ten okamzik :) Muze v tomto bode jeste napriklad bezet detached vlakno?
Jo, zničit heap v běžícím procesu samozřejmě jde. Ale já teda nepotkal platformu, kde by se při ukončování likvidoval normální heap. Vždycky to zůstalo viset a tu paměť pak poklidil OS. Spousta programů nechává viset objekty, které nepotřebujou volat destruktory. Takže příčetné runtimy se úklidem heapu na konci neobtěžují. Akorát Valgrind a spol. v takovém případě kvičí.

Moment moment, jde tohle udelat pomoci standardniho C++ runtimu? (tj. NE volanim noveho processu z C kodu). Predpokladam, ze to bude nejaky unixovy system call, ne?

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #28 kdy: 03. 08. 2022, 14:48:34 »
Ale abych se vratil k otazce.

Trochu to prezenu, abych zduraznil absurditu :) Je mozne pristoupit k objektu na heap po korektnim zniceni cele heap v bezicim procesu? Tj. dobehnou vlakna, znici se heap a TED je ten okamzik :) Muze v tomto bode jeste napriklad bezet detached vlakno?
Jo, zničit heap v běžícím procesu samozřejmě jde. Ale já teda nepotkal platformu, kde by se při ukončování likvidoval normální heap. Vždycky to zůstalo viset a tu paměť pak poklidil OS. Spousta programů nechává viset objekty, které nepotřebujou volat destruktory. Takže příčetné runtimy se úklidem heapu na konci neobtěžují. Akorát Valgrind a spol. v takovém případě kvičí.

Moment moment, jde tohle udelat pomoci standardniho C++ runtimu? (tj. NE volanim noveho processu z C kodu). Predpokladam, ze to bude nejaky unixovy system call, ne?
Můžete mít několik heapů tak, že použijete víc alokátorů. Nebo ve winapi máte třeba CreateHeap, takže si můžete vytvořit další heapy.

V c++ standardní knihovně nemáte možnost si nějaké další heapy přímo vytvořit, ale jinak je to na víc heapů připravené. Přece jenom, alokátor v kontejnerech není nic jiného než handle k nějakému heapu.

Re:Lifetime static/global/heap-allocated objektu v C++
« Odpověď #29 kdy: 03. 08. 2022, 17:00:36 »
"Slysel jste nekdy o YAGNI? A kdybych mel vzdycky delat jen to, co se po mne chce, asi bych byl porad jeste junior... :)"
No nevím, pocit že jsi chytřejší než ostatní je často dosti příznačné pro ... doplň si sám. Jak se říká: "Never trust a programmer who says he knows C++"  ;)