Kezdőoldal » Számítástechnika » Programozás » C++ constructor stack igénye?...

C++ constructor stack igénye? Lehet-e virtual fn egy constrálásban?

Figyelt kérdés

Egy objektum konstruálását adott llvm-gcc (xcc) fordító úgy teszi, mintha virtuális függvény lenne a constructor (vagy a hívási fában valahol).


Ennek van bármiféle teoretikus oka?


Szerintem sose virtual egy constructor, mert mindenhol a konstruálás során tudjuk hogy milyen tipusúak a memberek és ősök, amit konstruálni kell, és tudjuk azok pontos tipusát, ergo a constructorokat is.


Adott llvm-gcc compilert (xcc) használva ebben a környezetben minden függvényre kiszámítják a stack szükségletet, ezáltal biztosítva, hogy egy függvényt hívó kód elegendő stack-et allokáljon belépéskor. Ennek amúgy nem lenne sok értelme, de itt több szálú kód fordul, és több stack van, blabla.... Szóval a lényeg, hogy a compiler felcimkézi a függvényeket, hogy mennyi a max stack szükséglet.

Teoretikusan egy virtual fn esetében érthető (több gyerek esetén) hogy a tipus ismeretében se tudjuk hogy melyik virtual fn implementáció fog meghívódni futáskor, igy a max stack se tippelhető. Ez világos... Ennek az az alapja, hogy egy már létező objektumról nem tudjuk hogy miképpen lett konstruálva. Márpedig a virt fn meghívása azzal kezdődik, hogy feloldunk egy tipusos pointert, az az infó elvész, hogy a túloldalon a gyerekek közül melyiket tartalmazza futásidőben a vmt... (de egy constructor csak a tényleges allocator esetén hívodik meg, ami mindig tipusos) Destructor esetében tudjuk, hogy létezik virtual, de constructor esetében nem látom momentán semmi értelmét. :)


A jelenség az, hogy bárhol meghívhatok egy member függvényt, ha tudom a tipusát, csak virtual member fn-t nem, mert akkor a linker számára hiányzik a stack infó (meg kell adni kézzel). Nos, a helyzet úgy fest, hogy a constructorok esetén is hiányzik ez az infó a linkernek, hibát ad akkor, ha egy fn allokálni készül egy osztály példányt (ott constructor hívás lesz). (ha nem allokál, hanem obj ptr van akkor minden oké). Magyarra lefordítva a fordító virtuál fn-ként fordítja (nem ismeri a hivási fáját) a constructoroknak... Miért?


Egyszerű esetben is elhasal a linkelés, nagyon nem tudok másra gondolni, mint félbehagyták a c++ fordító ezen részét :). Mivel teoretikusan szerintem ismertnek kéne lenni egy osztály constructor fn hivási fájának minden esetben ami eszembe jut...


A fennti probléma/kérdés olyan esetre vonatkozik (sajnos), amikor sehol sincs vmt használat , semmi virtual nincs a kódban, és egy constructor blockban sincs fn hívás. (alap)



2015. júl. 12. 12:30
 1/6 anonim ***** válasza:

>> Szerintem sose virtual egy constructor, mert mindenhol a konstruálás során tudjuk hogy milyen tipusúak a memberek és ősök, amit konstruálni kell, és tudjuk azok pontos tipusát, ergo a constructorokat is.


A konstruktor sohasem virtuális. A virtuális függvény azt jelenti, hogy az objektumhoz tartalmaz egy pointer (a memóriában az elején) egy virtuális függvénytáblára ami az osztály sajátja és ebben vannak a virtuális függvényekre mutató pointerek. A konstruktor nem lehet ilyen.


Amiről te bészélhetsz, bár elég zavaros az a fordító számára átlátszatlan függvények esete. Amikor csak a deklarációt látja a header-ből, de nem látja a definíciót.


Küldjél példakódot, mert ezt én nem tudom produkálni gcc-vel.

2015. júl. 12. 13:37
Hasznos számodra ez a válasz?
 2/6 A kérdező kommentje:

Köszi a választ. A fordító és a linker között olyan nyilvántartás van, ami alapján mellékes hogy .h vagy .cpp fileban volt eredetileg (részben vagy teljesen) leírva a constructor. Ezért nem menteném fel a linkert a helyes eredménytől. :) Mire linkelésig jutunk, minden tipus ismert (kéne hogy legyen). Tehát a fennti esetben azt a hibaüzenetet adja a fordító, hogy egy ismert típusú fn-ről nem tudja a stack szükségletet eldönteni és nem azt, hogy nem ismer egy tipust. Ergo a constructorhoz nem készül el az nstack info...

Lehet olyan, hogy egy member ptr-t a constructor on-the-fly construál, szóval meghív egy másik osztály constructorát. Ebből fakadhat mondjuk rekurzió, ami már tényleg problémás...

Azért problémás a rekurzió, mert minden fn-t ismerünk, de nem ismerjük hányszor fogja meghivni önmagát... Mondjuk ez is elég vad (nem, nem volt rekurzió se a kódomban) :).


A szitu az, hogy van egy spéci cpu aminek a linkere részben rossz szerintem. De csak akkor, ha multithreades pontról hivnak (tehát az esetek egy részében) egy cpp függvényt, és csak akkor ha konstruálunk vagy virtuális fn-t hivunk. Az utóbbit értem, az elsőben nem látom a probléma okát. A linker működése komplikáltabb, ha többszálú pontra készít tárgykódot. A komplikált algoritmusai pedig felhasználják az nstack információt, ami a két említett esetben nincs. És a kérdésem arra irányult, hogy elméleti okból nincs-e :) Rekurziv, vagy virtual fn esetében értem hogy elméleti okból nincs. Constructor esetében nem látom hol van itt a rekurzió, vagy a virtual fn hívás lehetősége...


Irok egy kódot:

class A{public: int a; int fn1(){return a++;} };


//ez a fn miatt linker errort kapunk a constructorra

A* getSingleton(){

static A* p=new A(); //constructor hívás az első belépéskor fut le, mert static.

return p;

}

//ez no para

void wrapper1(){

A* pA= getSingleton(); //beszerezzuk az obj ptr-t.

int a= pA->fn1(); //itt tag fn-t hivunk.

}

2015. júl. 12. 14:15
 3/6 A kérdező kommentje:
Ja, azt elfelejtettem írni, ha a getSingleton() fn-ből a static -os constructoros sort global-ba kiteszem, vagy a main()-be egyéb egyszálú helyre mozgatom, akkor csont nélkül fordul...
2015. júl. 12. 14:25
 4/6 anonim ***** válasza:
Köszönöm a példakódot. Szerintem ez nem a virtuális függvénnyel és nem a konstruktorral függ össze, hanem a getSingleton static initializálásával. A fordító általában egy rejtett flaggel biztosítják az egyszeri létrehozást. Ez a flag általában nem szálbiztos, illetve csak C++11-től követelmény. Nem lehet, hogy ezt nem tudja megfelelően kezelni?
2015. júl. 12. 16:38
Hasznos számodra ez a válasz?
 5/6 anonim ***** válasza:
0%
Használj olyan fordítót amivel lefordul :D
2015. júl. 12. 17:09
Hasznos számodra ez a válasz?
 6/6 A kérdező kommentje:

Erre a static-os problémára nem gondoltam. :) Köszi, utána járok mit fordít arra. Ettől független a bajom.


Elméleti okát keresem annak, hogy a costructorok fája mikor nem bejárható. Ott tartunk, hogy ha kézzel beleírok egy virtual vagy egy rekurziv fn hívást a constructor kódjába, csak akkor nem. De alapból egy sima konstruálás mindig bejárható.

Rákérdezek a fejlesztőknél is, csak nem akartam valami bődületes baromsággal indítani :). Mert úgy fest valamit nem fejeztek be a fordító kódjában. :) Az is lehet hogy az egész constructor fa bejárás nincs befejeze (?) :) erre irok majd egy tesztet... De lényeg hogy valami nem jó...


A cucc egyébként egy olyan CPU-ra fordít amin hw-esen támogatott a szálkezelés és erőforrás allokáció. Szóval true párhuzamos futás van egyszerre sok magon. Ez kb azt jelenti, hogy egy cpu utasítás hatására el tud indulni n darab másik szabad magon ugyanez a kód (folytatása), úgy hogy mindegyik stack-et X-el eltolja.(Ahhol az X csak annyi, amennyi az adott ponton szükséges). Magyarán a fordító olyan kódot készít ami lehetővé teszi ezt, a cpu pedig kvázi úgy mint egy ugró utasításnál, natívan végrehajtja. Ez veszett gyors, a fordítónak meg az a feladata, hogy megadja a stack méretet minden fn-re, kivéve amire elméletileg lehetetlen megadni... Ez volt itt a question. :)

2015. júl. 12. 21:28

Kapcsolódó kérdések:




Minden jog fenntartva © 2025, www.gyakorikerdesek.hu
GYIK | Szabályzat | Jogi nyilatkozat | Adatvédelem | Cookie beállítások | WebMinute Kft. | Facebook | Kapcsolat: info(kukac)gyakorikerdesek.hu

A weboldalon megjelenő anyagok nem minősülnek szerkesztői tartalomnak, előzetes ellenőrzésen nem esnek át, az üzemeltető véleményét nem tükrözik.
Ha kifogással szeretne élni valamely tartalommal kapcsolatban, kérjük jelezze e-mailes elérhetőségünkön!