- Samsung Galaxy Watch7 - kötelező kör
- Samsung Galaxy Watch6 Classic - tekerd!
- Mobil flották
- Milyen okostelefont vegyek?
- Redmi Note 13 Pro 5G - nem százas, kétszázas!
- Google Pixel 9 Pro XL - hét szűk esztendő
- Samsung Galaxy S24 Ultra - ha működik, ne változtass!
- One mobilszolgáltatások
- Egy szenzor, két zoomkamera: újraírta a Huawei a mobilfotózás történetét
- Magyarított Android alkalmazások
Új hozzászólás Aktív témák
-
jattila48
aktív tag
válasz
EQMontoya #3196 üzenetére
A gcc generálja a thunk kódot, a virtuális hívást, és még nem tudom mit. Mint ahogy a VS is, ha nem tud a BodyClass-ról semmit. Bármelyik fordítónak a "legrosszabb" esetre kell készülni (többszörös virtuális öröklés, virtuális tfv.), ha csak a BodyClass forward deklarációját látja, és semmi egyéb segítséget nem kap. Magától nem találhatja ki hogy "mizu" van. Nem tudom, hogy a gcc-nek vannak-e erre kulcsszavai, nem nagyon használom. A VS-ben is csak most találtam rá. Mondjuk member function pointert sem igen használtam, és gyakorlatban a forwarding fv. hívás sem túl nagy overhead, inkább csak elméletileg érdekelt a dolog. A C++-ból azért mindig van mit tanulni.
-
dobragab
addikt
Szerintem egy nagy példán belül az összes tárolót nem tudod bemutatni. Ha találsz is egy példát, az vagy túl nagy lenne, vagy erőltetett. Jól van az, hogy mindenre találsz külön-külön példát.
-
jattila48
aktív tag
válasz
jattila48 #3189 üzenetére
Na megint tanultam valamit. Ezt írtam:
"Jó lenne, ha a forward deklarációban meg lehetne mondani, hogy a BodyClass teljesen közönséges osztály, nem örökölt senkitől (főleg nem többektől) és nincs virtuális tfv.-e (még emiatt is lehet ez az igazítás). Akkor talán nem generálná ezt az ilyen osztályokra amúgy tényleg fölösleges igazító kódot. Ilyet sajnos tudtommal nem lehet a C++-ban."És VS-ben lehet! handle_class.h-ban:
class __single_inheritance BodyClass;__single_inheritance kulcsszó a forward deklarációban a megoldás! Így már igazító kód nélkül fordít, és főleg jól. Ha még azt is meg lehetne mondani, hogy az mfp nem virtuális fv.-re mutató member function pointer, akkor az indirekt címzésű call helyett is lehetne direkt címzésűt fordítani (bár ez nem nagy veszteség).
-
EQMontoya
veterán
válasz
katona.jozsi #3193 üzenetére
Mapet szerintem a [] op. mókás viselkedésével érdemes bemutatni.
Pl. bemeneten kapott szövegben a szavak megszámlálása és ebből statisztika készítése. (ez ugye kb. tíz sor) -
katona.jozsi
aktív tag
Sziasztok!
Tudnátok-e olyan példaprogram ötletet mondani, ahol az STL tárolók használatát jól betudnám mutatni?! Nincs ötletem, hogyan is lehetne jól szemléltetni a köztük lévő különbséget, OOP szemlélettel mutatnám be, de egy példán keresztül. (Például egy snake programnál jól használható a vector és a deque, de a többi tároló, akkor kimarad)Köszi előre is a tanácsokat!
-
jattila48
aktív tag
válasz
jattila48 #3191 üzenetére
Debuggolással sikerült kideríteni, hogy az igazító kód valóban a pimpl pointert igazítja. Akkor van rá szükség, ha pl. a BodyClass osztály két ösosztálytól örököl publikusan, méghozzá az f tfv.-ét a másodiktól örökli. Mivel a forward deklaráció miatt a fordító nem látja a teljes BodyClass osztály definíciójat, így erre az esetre mindenképp fel kell készülnie. A pimpl az egész objektumra mutat, de ez az első ősosztály részét jelenti az objektumnak. Ezért, ha a második ősosztályból örökölt tfv,-re mutat az mfp, akkor a pimpl-nek is a BodyClass objektum második ősosztály részére kell mutatnia. Ezt végzi ez a bizonyos igazító thunk kód. Ha a teljes BodyClass definíciót látja a fordító, akkor el tudja dönteni, hogy a BodyClass nem örököl többszörösen, ezért nincs szükség a thunk kód generálására. Az első
004116D6 cmp dword ptr ds:[4168B4h],0
sort nem értem, mert az eredméntyét nem befolyásolja, hogy a tfv. virtuális-e vagy sem, az sem hogy örökölt-e vagy sem. De a hamis kimenetelkor lefutó ágból nekem mégis úgy tűnik, hogy valami virtuális dologgal lehet összfüggésben. Ha a tfv. virtuális, akkor a kód végén az indirect címzésű call virtuális hívást megvalósító kódra ugrik. Tehát ezért kellet a call-nak indirekt címzésűnek lenni. Ha látná, hogy a tfv. nem virtuális, akkor elvileg direkt címzéssel is meghívhatná, azonban ekkor sem teszi. -
jattila48
aktív tag
válasz
jattila48 #3190 üzenetére
Közben kicsit jobban belegondoltam, és az igazító kód valószínűleg a többszörös öröklődésből adódó this pointer igazítást is, és az esetleges virtuális fv. híváshoz szükséges vftbl pointer igazítást is elvégzi. Az incomplete BodyClass forward deklaráció miatt a fordító nem látja, hogy a BodyClass *pimpl pointer valójában egy BodyClass-ból publikusan leszármazott osztályra is mutathat, sőt az is lehet, hogy az osztálynak egy másik publikus ősosztálya is van, amitől előbb örököl, mint a BodyClass-tól:
class DescClass : public UnknownClass, public BodyClass{...}
A handle_class.cpp-ben pedig a HandleClass ctor.-a:
HandleClass::HandleClass():pimpl(new DescClass ()){}Ebben az esetben a pimpl valójában az UnknownClass részre mutat (mivel az van előbb az ősök között), és nem a BodyClass részre, ahogy kéne. Ezért ha a DescClass * típusú pointert a pimpl értékül kapja, azt igazítani kell a BodyClass részre (ezt végzi egyébként a thunk kód többszörös öröklődés esetén).
Virtuális tfv. esetén a member function pointer szintén fordítás idejű konstans, azonban nem a tfv. közvetlen címe, hanem a virtuális fv. táblában a rá vonatkozó bejegyzés indexe (ez nem biztos, ezt csak így gondolom). Ezért az esetleges öröklődésből adódó vftbl címet is igazítani kell, mivel a fordító ugye nem látja, hogy a BodyClass valójában egy ebből leszármazott osztállyal példányosult. Az igazító kódban szerintem az első sor
004116D6 cmp dword ptr ds:[4168B4h],0
annak vizsgálata lehet, hogy tfv. virtuális-e. Ha nem, akkor egyszerűen a thunk kód kerül végrehajtásra a linkelési időben kitöltött információk alapján. Ha virtuális, akkor a másik ágban a vftbl. megfelelő beállítása, és a thunk végrehajtása történik. Mivel rossz működés esetén ebben az első utasításban rossz a "globális" cím, ezért gondolom, hogy a linker (vagy a betöltő) ront el valamit. Az, hogy a call ezután indirekt címzéssel történik, arra utal, hogy futási időben dől el, hogy milyen kódrészletet kell végrehajtani (talán maga az esetleges virtuális hívás?). Remélem érthető volt, és elnézést ha kicsit hosszúra nyúlt. -
jattila48
aktív tag
válasz
jattila48 #3189 üzenetére
"Úgy tűnik, hogy a forward deklarációval nincs elég információja a BodyClass osztályról, hogy a pimpl és az mfp alapján meghatározza a BodyClass f tfv.-ének valódi címét."
Ez butaság, a BodyClass f tfv.-ének címe konstans, és jól van eltárolva. Az aktuális BodyClass objektumra mutató pipl-et akarja hozzá igazítani. Talán mégis inkább virtuális tfv.-re mutató member function pointer esetén lehet erre szükség. Ha tudná, hogy az f nem virtuális, akkor erre nem is lenne szükség. Ez csak tipp.
-
jattila48
aktív tag
válasz
jattila48 #3184 üzenetére
A "fölösleges" kód akkor keletkezik, ha handle_class.h-ban a BodyClass incomplete type-ként forward deklarálva van. Ha beinkludolom a teljes body_class.h-t, akkor "szép" kódot generál. Ekkor persze nincs értelme a pimpl-nek. Úgy tűnik, hogy a forward deklarációval nincs elég információja a BodyClass osztályról, hogy a pimpl és az mfp alapján meghatározza a BodyClass f tfv.-ének valódi címét. Mintha a pimpl-et akarná különböző információk alapján igazítani, ahogy a this-t szokta igazítani a thunk kód többszörösen örökölt osztályok esetén. Jó lenne, ha a forward deklarációban meg lehetne mondani, hogy a BodyClass teljesen közönséges osztály, nem örökölt senkitől (főleg nem többektől) és nincs virtuális tfv.-e (még emiatt is lehet ez az igazítás). Akkor talán nem generálná ezt az ilyen osztályokra amúgy tényleg fölösleges igazító kódot. Ilyet sajnos tudtommal nem lehet a C++-ban. Egyébként a kódban valószínűleg csak cím hibás, mégpedig a
004116D6 cmp dword ptr ds:[4168B4h],0
sorban a 4168B4. Amikor rosszul fut, akkor ez a cím unicode sztringekre mutat, vagyis nyilvánvalóan rossz. Amikor jól fut, akkor különböző globális konstansok lehetnek itt és környékén (ha jól fut, akkor 0). Mégsem a const deklarációtól függ, hogy jó-e vagy nem, mert újra buildeléskor const-tal is elromlott. Talán a linker lesz a hibás. Egyébként az LLVM erre a kódra assertion failed-del elszáll, és kéri, hogy a hibajelentést küldjem be. Csak a gcc tudta minden gond nélkül buildelni. -
jattila48
aktív tag
válasz
jattila48 #3186 üzenetére
A másik programomban teljesen hasonló kódra a VS ezt fordította:
auto pimpl=hc.pimpl;
00426AAF mov eax,dword ptr [ebp-1Ch]
00426AB2 mov ecx,dword ptr [eax]
00426AB4 mov dword ptr [ebp-28h],ecx
.
.
.
auto sc=hc.f(1);
00426ABF push 1
00426AC1 lea eax,[ebp-74h]
00426AC4 push eax
00426AC5 mov ecx,dword ptr [ebp-1Ch]
00426AC8 call HandleClass::f (04113CFh)
.
.
.
auto sc2=(pimpl->*hc.mfp)(2);
00426AD7 mov esi,esp
00426AD9 push 2
00426ADB lea eax,[ebp-1D4h]
00426AE1 push eax
00426AE2 mov ecx,dword ptr [ebp-28h]
00426AE5 call dword ptr ds:[42B8A0h]Látható, hogy a mfp-én keresztüli hívás előtt nincs befordítva a "fölösleges" kód. Egyébként a kétfajta hívás kódja teljesen hasonló, csak az első call direkt címzéssel, a második pedig indirekt címzéssel történik. Viszont a második call már közvetlenül a BodyClass f tfv.-ét hívja, vagyis valóban nincs forwarding call overhead (ami egyébként elég jelentős). Fórumokon (pl. StackOverflow) azt olvastam, hogy a pimpl-et nem lehet enélkül megcsinálni. Ezek szerint mégis. Ez azért működik, mert az incomplete type-ok member pointerei is forward deklarálhatók.
-
EQMontoya
veterán
válasz
jattila48 #3186 üzenetére
Simán elképzelhetőnek tartom, hogy compiler bugot fogtál.
Először azt hittem, ott lehet benne buktató, hogy egy static ptr úgy kap értéket, hogy akitől kapja, az member volt, ezért mondjuk move-olódhatna máshová, de ez már utána nem befolyásolja a staticot, mert közvetlenül mutat, nem ezen keresztül, tehát nem okoz gondot.
-
jattila48
aktív tag
Attól tartok, nem egészen érted miről van szó. A member pointerek nem függenek egyetlen példánytól sem, hanem az osztály (nem az objektum!) tagjaira hivatkozó fordítás idejű konstansok. Úgy kell elképzelni, mint offset-et, ami az osztály kezdetéhez képest mutatja az adott tag helyét az osztályban. Pl. struct semmi{int a; int b;} osztályban a semmi::* pa=&semmi::a és semmi::* pb=&semmi::b deklarációkkal a pa=0 és pb=4 konstans értékeket vesz fel (feltehetőleg), mivel az a tag offsetje az osztályhoz lépest 0, a b-é pedig 4 (ha az a mérete 4 byte volt). Ugyanígy (nem virtuális) tfv.-ekre is, csak ekkor nem az offset, hanem a tfv. címe mint fordítás idejű konstans kerül a member function pointerbe. A HandleClass::mfp nálam ilyen member function pointer, ami történetesen a BodyClass::f tfv.-ének címét tartalmazza (és ez független a BodyClass bármely példányától, egy közönséges fv. cím). Ezért, mivel nem függ sem a HandleClass, sem a BodyClass egyetlen példányától sem, nyugodtan lehet statikus, hiszen minden példányban ugyanaz a konstans érték. Amikor (pimpl->*hc.mfp)(2); formában hívom a BodyClass f tfv.-ét, akkor ez nem azt jelenti, hogy az mpf a pimpl által mutatott objektum tagja lenne (mint ahogy a ->* miatt első ránézésre tűnik), hanem a BodyClass::f tfv. kapja a pimpl-et első paraméterként, 2-őt második paraméterként, (mint ahogy a tfv.-ek első paramétere mindig az aktuális példányra mutató this pointer), az mpf pedig történetesen a hc statikus tagja. Egyébként ahogy írtam, ha az mpf-et const-ként deklarálom akkor működik, különben pedig futási hibával elszáll. A VS kever valamit, mert a gcc jól fordítja. A VS is lefordítja, csak szerintem rosszul.
-
MageRG
addikt
válasz
jattila48 #3184 üzenetére
Nem értek annyira a C++ programozáshoz, de nekem fura hogy egy static memberbe akarsz belepakolni egy másképp példányosodó valamit.
A HandleClass::mfp közös az összes HC-ben, ugyanazt a BodyClass példány memberét hívja.
De a HandleClass::f meg egy-egy külön BodyClass példány membert hív, ami a konstruktorban jön létre.
Vagyis a két hívás *vára nem ugyanazt csinálja.
Akkor lenne ugyanaz, ha a *pimpl member is statikus lenne.De ez csak az én "két centem".
-
jattila48
aktív tag
válasz
jattila48 #3182 üzenetére
Úgy néz ki, megoldódott a probléma. Ha az mfp member function pointert const-nak deklarálom, úgy jól működik. handle_class.h-ban:
int (BodyClass::* const mfp)(int);
handle_class.cpp-ben:
int (BodyClass::* const HandleClass::mfp)(int)=&BodyClass::f;
pimpl_proba.cpp-ben visszaírtam egy utasításba a debug miatt több sorra szedett hívást:
BodyClass *pimpl=hc.pimpl;
n=(pimpl->*hc.mfp)(2);Szerintem const nélkül is jól kéne működnie, úgyhogy a VS-ben lehet hiba. Továbbra sem értem azonban, hogy mi az a "fölöslegesnek" tűnő kód, amit a hívás előtt generál (ez volt hibás ha nem const volt az mfp):
004116D6 cmp dword ptr ds:[4168B4h],0
004116DD jne main+80h (04116F0h)
004116DF mov eax,dword ptr [pimpl]
004116E2 add eax,dword ptr ds:[4168ACh]
004116E8 mov dword ptr [ebp-100h],eax
004116EE jmp main+0A9h (0411719h)
004116F0 mov ecx,dword ptr [pimpl]
004116F3 add ecx,dword ptr ds:[4168B0h]
004116F9 mov edx,dword ptr [pimpl]
004116FC add edx,dword ptr ds:[4168B0h]
00411702 mov eax,dword ptr [edx]
00411704 mov edx,dword ptr ds:[4168B4h]
0041170A add ecx,dword ptr [eax+edx]
0041170D add ecx,dword ptr ds:[4168ACh]
00411713 mov dword ptr [ebp-100h],ecx
00411719 mov esi,esp
0041171B push 2
0041171D mov ecx,dword ptr [ebp-100h]
00411723 call dword ptr ds:[4168A8h]A pimpl-et igazgatja, de nem tudom miért. Másik programomban ez nincs. Valami hasonlót a gcc is csinál. Szerintetek mi lehet ez?
-
b_alazs
tag
Sziasztok!
Adatbázis építéshez keresek programozót.
A technikai felépítés kapcsán nincs kikötés.A feldat sajátosságai miatt az elvárások:
- miskolci lakos
- heti 1-2 óra személyes egyeztetésMinden egyéb információ privátban.
Üdv,
Balázs -
jattila48
aktív tag
válasz
jattila48 #3181 üzenetére
Közben annyit sikerült kideríteni, hogy ha a HandleClass::mfp BodyClass tfv.-re mutató member function pointer nem statikus, hanem sima tag, akkor jól működik. Azzal, hogy az mfp statikus, azt akartam elkerülni, hogy a hc-én keresztül "meg kelljen hivatkozni", hiszen ez is overhead lenne. Nem értem miért nem működik, hiszen a a member pointerek fordítás idejű konstansok, ezért lehet az mfp statikus. Ugyanakkor lefordul, tehát a VS szerint is lehet.
-
jattila48
aktív tag
Sziasztok!
Egy olyan pimpl megvalósítást szeretnék csinálni, amiben nincs a handle osztály (ez tartalmazza a pimpl pointert) tfv.-einek hívásából adódó forward hívás overhead. "Normálisan" a handle osztály tfv.-ei csak egy forwardolást csinálnak a body osztály (ebben van az implementáció) tfv.-einek hívásával pimpl->f() formában. Ezt az overheadet akarom elkerülni, vagyis a body osztály tfv.-eit közvetlenül akarom hívni.
Példa://pimpl_proba.cpp file
#include "handle_class.h"
int main(int argc,char *argv[])
{
HandleClass hc;
BodyClass *pimpl=hc.pimpl;
int n=0;
n=hc.f(1);
int (BodyClass::*ff)(int)=HandleClass::mfp;
n=(pimpl->*ff)(2);
n=1;
return 0;
}
//handle_class.h file
#ifndef _HANDLE_CLASS_
#define _HANDLE_CLASS_
class BodyClass;
struct HandleClass{
HandleClass();
~HandleClass();
BodyClass *pimpl;
int f(int n);
static int (BodyClass::*mfp)(int);
};
#endif
//body_class.h file
#ifndef _BODY_CLASS_
#define _BODY_CLASS_
class BodyClass{
public:
BodyClass();
int f(int);
private:
int a;
};
#endif
//handle_class.cpp file
#include "handle_class.h"
#include "body_class.h"
HandleClass::HandleClass():pimpl(new BodyClass()){}
HandleClass::~HandleClass(){delete pimpl;}
int HandleClass::f(int n){
return pimpl->f(n);
}
int (BodyClass::*HandleClass::mfp)(int)=&BodyClass::f;
//body_class.cpp file
#include "body_class.h"
BodyClass::BodyClass():a(5){}
int BodyClass::f(int n){
return a+n;
}A pimpl_proba.cpp fájl nem függ a body_class.h fájltól, vagyis ha a BodyClass-ban megváltozik az implementáció, nem kell újrafordítani a pimpl_proba.cpp-t. Azonban az n=hc.f(1); fv. hívás a return pimpl->f(n); fv. hívással két fv. hívást eredményez, amit szeretnék elkerülni. Ezért a HandleClass osztálynak van egy statikus BodyClass tfv.-re mutató member function pointere, ami a BodyClass f tfv.-re mutat. Az n=(pimpl->*ff)(2); utasítás közvetlenül ezen keresztül hívja meg a BodyClass f tfv.-ét, és így megspórolok egy forwarding fv. hívást (csak a debuggolás miatt lett több sorra szedve). Ez így lefordul VS2012 alatt, azonban access violation-nel elszáll. Belenéztem a lefordított assembly kódba, és szerintem hibás amit generál,és részben "fölöslegesnek" tűnik. Ugyanakkor gcc-vel simán lefordul és fut. Bár a gcc is mintha "fölösleges" kódot generálna a közvetlen hívás előtt (talán this pointer igazítás, virtuális tábla keresés?). Ezt a módszert már használtam nagyobb programban is, ott a VS is jól fordította és a "fölösleges" kódnak sem láttam nyomát.
Kérdés: mi lehet a baj?
A válaszokat előre is köszönöm, de kérem, aki hozzászól, a lényegre koncentráljon, ne arra hogy minek ez nekem, a pimpl miért nem private, és miért nem unique_ptr, stb. -
jattila48
aktív tag
válasz
jattila48 #3176 üzenetére
Tehát így már jó:
struct tempfv{
int operator()(){return 42;}
};
template<typename R,typename F> struct Temp
{
int f(){
return F()();
}
};
template <template<typename R,typename F> class T,typename R,typename F> struct TempTemp
{
T<R,F> t;
int f(){return t.f();}
};
TempTemp<Temp,int,tempfv> t; -
jattila48
aktív tag
Egy másik probléma:
Szerintetek ez miért nem fordul le?int tempfv(){
return 42;
}
template<typename R,R (*F)()> struct Temp
{
int f(){
return F();
}
};
template <template<typename R,R (*F)()> class T,typename R,R (*F)()> struct TempTemp
{
T<R,F> t;
int f(){return t.f();}
};
TempTemp<Temp,int,tempfv> t;Ha az F nem függvénypointer hanem functor, akkor lefordul. Úgy tűnik, hogy a template template paraméter paramétere nem lehet függvénypointer. Igaz ez? VS ezt írja ki:
error C3201: the template parameter list for class template 'Temp' does not match the template parameter list for template parameter 'T' -
jattila48
aktív tag
válasz
EQMontoya #3174 üzenetére
Valószínűleg nem ez a legjobb megoldás, úgyhogy le is tettem róla. Ettől a kérdés még elméletileg érdekes. A pimpl marad, viszont az int template paramétert (amihez a static_for kellett volna), megszüntetem. Azt hiszem, a pimpl idióma egyébként sem ajánlható template-ekben (pont az explicit példányosítás szükségessége miatt), de nekem most nagyon jól jön, és nem az implementáció elrejtése vagy a gyorsabb fordítás miatt.
-
-
jattila48
aktív tag
válasz
EQMontoya #3172 üzenetére
Azért, mert a példányosítandó template pimpl idiómát használ, ezért nem a header-ben vannak a tfv.-ek definíciói, hanem külön cpp fájlban. Egy másik cpp fájl szeretné használni a template egy osztálypéldányát, de a pimpl miatt csak a pimpl-es template-ből deklarál osztályt. A handler osztályt a template definíció helyén (a cpp fájlban) ezért explicit példányosítani kell.
-
jattila48
aktív tag
válasz
EQMontoya #3170 üzenetére
Köszi a választ! Ez lényegében ugyanaz, mint az én megoldásom, és a bajom is ugyanaz vele. A P tagfüggvényeit mind meg kell hívni (p.doSomething()
, ha azt akarjuk, hogy példányosuljanak. Valami olyasmit szeretnék, mint az explicit template példányosítás, de static_for-ban. Az explicit template példányosításkor nem kell meghívni a tfv.-eket, de mégis mind példányosulnak. Jó lenne, ha mondjuk egy sima template példány deklarálásakor ki lehetne kényszeríteni a tfv.-ek példányosulását is. Erre nincs mód?
A smiley ; és ) akart lenni. -
EQMontoya
veterán
válasz
jattila48 #3169 üzenetére
Csinálsz egy template classt, aminek van két int paramétere.
Az első hívásnál az első értelemszerűen 0, a második N.Ezzel tudod mindet példányosítani, és meghívni rajtuk valamit. Az más kérdés, hogy utána
Valahogy így:
template<int from, int to>
struct static_for
{
void operator()()
{
P<from> p;
p.doSomething();
static_for<from+1, to>()();
}
};
template<int to>
struct static_for<to, to>
{
void operator()()
{}
}; -
jattila48
aktív tag
Egy int paraméterű template-et szeretnék explicit példányosítani egy bizonyos egész számig az összes ennél kisebb argumentummal. Hogy lehetne ezt egyszerűen megtenni?
template<int N> struct P{
int f();
};Ha pl. 3-ig akarom példányosítani, akkor ne kelljen 3-szor kiírni:
template struct P<0>;
template struct P<1>;
template struct P<2>;hanem rekurzívan valahogy így:
template <int N> struct Instantiate
{
//Instantiate():x(i.p.f()){}
P<N> p;
Instantiate<N-1> i;
int x;
};
template <> struct Instantiate<0>
{
P<0> p;
};
template struct Instantiate<3>;Ezzel az a probléma, hogy elvégzi a template példányásítását a megadott argumentumig minden egész számra, azonban a tagfüggvényeket nem példányosítja, ha csak a Instantiate template ctor-ában meg nem hívom azokat (kikommentezett sor). Ha kiírom a három explicit példányosítást, akkor persze a tagfüggvények is példányosulnak, de így nem. Szóval erre a problémára kellene valami szebb megoldás.
-
Nono, ebben a felevben szigoruan notepad++ es command linebol forditas. Vizsgan is ez lesz a kovetelmeny.
-
Sziasztok, egy kis segítség kéne
Félév végén cpp vizsga, nekiugrottam a cpp tanulásnak, kb. 0-ról. Javaban már van kicsit több tapasztalatom, de a C++ sajna messze áll még tőlem. Meg tudnátok mondani, hogy mi a probléma az alábbi kóddal? Undefined referencet kapok, nem találja a függvényt, de nem értem miért
Includeoltam a header file-t, akkor mi a baja?
main.cpp
#include <iostream>
#include "rectangle.h"
using namespace std;
int main(){
Rectangle rect;
rect.get_values();
cout << "Terulet: " << rect.area();
return 0;
}rectangle.cpp
#include <iostream>
include "rectangle.h"
using namespace std;
void Rectangle::get_values(){
cout<<"Szelesseg:";
cin >> width;
cout<<"magassag:";
cin >> height;
}
int Rectangle::area(){
return width*height;
}rectangle.h
#ifndef RECTANGLE_H
#define RECTANGLE_H
class Rectangle{
private:
int width, height;
public:
void get_values();
int area();
};
#endif -
Karma
félisten
-
EQMontoya
veterán
válasz
sztanozs #3154 üzenetére
Majdnem teljesen biztos vagyok benne, hogy működik, mert van ennyire okos a fordító. Csak abban nem vagoyk biztos, hogy szabvány szerint is kell-e működnie.
dobragab: ezzel az a baj, hogy a bool is legalább egy byte, amiből valami lesz, ha xorolgatod, de az szerintem nincs garantálva a szabványban sehol, hogy két igaz értékű boolnak minden esetben pontosan ugyanolyan memóriaképpel kell rendelkeznie. Tehát simán el tudnék képzelni olyan impelentációt, amiben előfordulhat, hogy két igaz értkű bool xorolása is igazt eredményez.
-
dobragab
addikt
Persze. C++-ban az eredeti is valid, csak nem sok értelme van.
Mondtam a csávónak: sel = !sel;
Válasz: Mindegy, megoldottam iffel.Időnként olyan érzésem van, hogy a javac dönti el, mit tud a nyelv, és mit nem. A szabvány luxus lenne. A mai napig nem tudom, miért nem fordult le.
-
pvt.peter
őstag
Köszönöm a választ ToMmY_hun, Ereshkigal és tboy93.
Közben én is megtaláltam a "Bjarne Stroustrup The C++ Programming Language 4th edition" -t, elég jónak tűnik. -
dobragab
addikt
Napi golden code. Régebben küldték, most eszembe jutott, és előtúrtam nektek
sel?(sel=false):(sel=true);
Slusszpoén: azért küldték, mert nem fordult le... jávában... És jávában ez tényleg invalid.
-
Én pont most kezdtem el a cpp-t az egyetemen, a tanár beszélt a Strostroup könyvről is, de azt nem ajánlotta annyira. Az kb. egy biblia, nem a legjobb abból tanulni, abban benne lesz minden, de nem olvasmányos. Amire azt mondta hogy jó olvasni, az a Scott Meyers féle effective c++, magyarul "hatékony c++" néven érhető el. Én ennek fogok szerintem nekiesni, valahogy abszolválnom kell a tárgyat
-
ToMmY_hun
senior tag
válasz
pvt.peter #3140 üzenetére
Nemrég én is feltettem ezt a kérdést, de nem kaptam rá választ.
Én Bjarne Stroustrup The C++ Programming Language 4th edition-t kezdtem el olvasni, eléggé frankó iromány. Kicsit száraz és nagy terjedelmű, cserébe alapos és a 11-es szabványnak megfelelő nyelvi elemeket használja.
-
pvt.peter
őstag
Sziasztok,
C# -ban fejlesztek immár kb. 3. éve, viszont szeretnék áttérni C++ fejlesztésre.
A kérdésem az lenne, hogy mik azok a könyvek amik alapján a legrövidebb idő alatt illetve a legjobban el lehet sajátítani a C++ specifikus dolgokat?
Jelenleg ezt a könyvet olvasom:
[Benedek Zoltán, Levendovszky Tihamér - Szoftverfejlesztés C++ nyelven]Előre is köszönöm,
Üdv,
Peti -
johnnie94
csendes tag
Sziasztok,
C-vel már foglalkoztam korábban, most C++ -t szeretnék elkezdeni tanulni. Windows 8.1 64bit alatt a CodeBlocks viszont nem fordít jól (?). Próbáltam különböző megoldásokat, de egyelőre nem jártam sikerrel. Esetleg van, aki ezt a párosítást használja, esetleg van valami ötlete?
Ha rossz helyen kérdeztem, elnézést.
Szép napot! -
jattila48
aktív tag
válasz
ny.erno #3127 üzenetére
Gondolom egy (vagy több) kereskedő szoftverről van szó, amit figyeltetni szeretnél. Pontosabban a tőzsdén zajló eseményeket szeretnéd figyeltetni, ami alapján a kereskedő szoftver is kijelzi az állapotot. Magához a szoftverhez nem fogsz tudni hozzáférni, de igazából nem is ez a cél. A weboldalt kéne figyelned. A kereskedő szoftverek is egy adott protokollon (valami HTTP-be ágyazott) kérik le az adatokat, és jelenítik meg. A figyelő programnak ugyanezt kéne tenni. Tehát ismerni kéne a protokollt, és be kell tudni kapcsolódnia a kereskedő szoftverrel fenntartott hálózati kapcsolatba. Erre egy proxy szerű program lenne megfelelő, ami a tőzsdei web oldallal kiépíti a kapcsolatot (ez általában hitelesítéssel történik), és proxyként viselkedik a kereskedő szoftver felé (a kereskedő szoftvernek nagy valószínűséggel beállítható proxy). Hát kb ennyi. Nem túl egyszerű, de nem is megoldhatatlan feladat. Leginkább a protokoll megismerése a kihívás, bár lehet, hogy ez valamiféle szabvány. Ha nem az, akkor pl. Burp proxyval lehet figyelni, kísérletezni, kitanulni. Lehet, hogy megérné.
-
ny.erno
tag
Sziasztok!
Őszinte leszek. Amiről itt beszélgettek, az nekem kínai, ezért konyhanyelven fogok kérdést feltenni.
Adott egy szoftver, ami figyel egy weboldalt, ahol sok infó van és ezek folyamatosan változnak. A tőzsde annyira jó példa, hogy szinte az is.
Szóval ez a program, ami figyel egy x weboldalat, ahol zajlanak az események. Ez a program sokkal gyorsabban reagálja le a weboldalnál a történéseket, gyorsabban lehet rajta műveleteket végrehajtani (a weboldal adataiból gazdálkodik, csak ott másodpercenként 4-5 alkalommal frissít, a szoftver meg mondjuk 20x).
Lehetséges-e egy olyan harmadik programot létrehozni, ami folyamatosan monitorozza ezt a tőzsdét figyelő programot, vagy akár a weboldalat, hogy ha valami hirtelen eltérés következik be (mondjuk beállítani 10%-os vagy afeletti eltérést), akkor azonnal jelezzen nekem, hogy A dolog történik B helyszínen? Elég ha csak jelez, a lépést az eredeti programon is meg tudom lépni, csak ott egyszerre 1 eseményt tudok nézni.Illetve lehetséges-e, hogy egyszerre ne csak azt a részt figyelje, ami éppen meg van nyitva, hanem más eseményeket is és azokon is jelezzen az ilyen mértékű eltérésre?
-
EQMontoya
veterán
Nem értem én az embereket.
Header file, deklarál egy osztályt, tagfüggvényekkel.
Cpp fileban kifejti a függvényeket.Ez eddig ok. Majd csinálj a cpp fileba egy unnamed namspace-t, amiben létrehoz egy egy soros függvényt. Mindezt használja egy helyen.
Azért ez az igazi overengineering, le a kalappal!
Azt az egy sort nyugodtan berakhatta volna abba a függvénybe, amiből meghívta ezt a műremeket.Az ellipszilonos lyére azzal tette fel a pontot, hogy ebben az egy soros kis függvényében is volt egy unused param warning. Én meg kimentem inkább teázni...
-
jattila48
aktív tag
válasz
jattila48 #3116 üzenetére
Hát, ez az algoritmus nem valami jó. Ugye mindig olyan számot hagytam el a sorozatból (pontosabban az első ilyet), amivel a legtöbb még ép mintasorozatot rontom el. Most egy kicsit módosítottam az algoritmuson, és az első ép mintasorozatból hagyom el azt az elemet, ami a legtöbb mintasorozatot rontja el. Ennek megfelelően a módosított forráskód:
#include <Windows.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
if(argc<3){
printf("Hasznalata: mintat_gyomlal <a gyomlalando sorozat hossza> <minta elemek 1... novekvoleg>");
exit(1);
}
int mintahossz=argc-2,sorozathossz=atoi(argv[1]);
auto minta=new int[mintahossz];
for(int i=0;i<mintahossz;++i){
minta[i]=atoi(argv[i+2]);
}
int minta_terjedelem=minta[mintahossz-1];
auto sorozat=new int[sorozathossz];
for(int i=0;i<sorozathossz;++i){
sorozat[i]=0;
}
for(int i=0;i<=sorozathossz-minta_terjedelem;++i){
for(int j=0;j<mintahossz;++j){
++sorozat[minta[j]+i-1]; //a tomb kezdeti feltotlese. az i.-edik elem azt jelzi, hogy az i+1 szam hany mintasorozatban szerepel
}
}
printf("A sorozatbol kihuzando szamok: ");
int nkihuzando=0;
while(1){
int kihuzando,max=0;
/*
//megkeressuk a legtobb mintasorozatban szereplo szamot, ez lesz a kihuzando+1 (a kihuzando indexu, mivel 0-val kezdodik az indexeles)
for(int i=0;i<sorozathossz;++i){
if(sorozat[i]>max){
kihuzando=i;
max=sorozat[i];
}
}
*/
//modositas: az elso ep mintasorozatbol keressuk ki a legtobb mintasorozatot elronto elemet
int i;
for(i=0;i<sorozathossz && sorozat[i]==0;++i);
if(i==sorozathossz)break;
for(int j=0;j<mintahossz;++j){
int n=i+minta[j]-1;
if(sorozat[n]>max){
kihuzando=n;
max=sorozat[n];
}
}
if(max==0)break;
printf("%d ",kihuzando+1);
++nkihuzando;
//A kihuzott szam utan a sorozat tomb elemeit csokkentjuk, hogy tovabbra is azt jelezze, a megmaradt ep mintasorozatok kozul hanyban szerepel az adott szam
for(int i=0;i<mintahossz;++i){
int n=kihuzando-minta[i];
for(int j=0;j<mintahossz;++j){
int k=minta[j]+n;
if(k>=0 && k<sorozathossz && sorozat[k]>0){
--sorozat[k];
}
}
}
}
printf("\r\nOsszesen %d db.",nkihuzando);
delete[] minta;
delete[] sorozat;
}A végén kiírom, hogy hány elemet hagytam el. Valamivel jobb eredményt ad mint az előző, de szerintem ez is távol áll az optimálistól.
-
-
jattila48
aktív tag
válasz
Boryszka #3095 üzenetére
Egy mohó algoritmust találtam ki a feladatodra, ami azért nem biztos, hogy optimális megoldást ad. Mintasorozatnak fogom nevezni az 1...N sorozatban bárhol megtalálható eltolt mintát. Tehát az pl. az 1,2,3,4,5,6,7,8 sorozatban az 1,3,4 mintának megfelelő mintasorozatok az 1,3,4; 2,4,5; 3,5,6; 4,6,7 és 5,7,8. Az elgondolás az, hogy a sorozatban megkeresem az első mintasorozatot, majd törlöm az egyik elemét. Ezzel elrontom az éppen aktuális mintasorozatot, és esetleg még másikakat is (legfeljebb annyit, amennyi a minta elemszáma, a példában ez 3). Azt az elemet fogom elhagyni, amelyik a legtöbb mintasorozatot rontja el. Ha több ilyen is van, akkor az elsőt veszem. Ezután az eljárást megismétlem. Megint veszem az első ép mintasorozatot (az elrontottak már nem lesznek tekintetbe véve), és megont elhagyom azt az elemét, amely a legtöbb mintasorozatot rontja el. És így tovább, egészen addig, amíg már nem lesz ép mintasorozat. Írtam is erre egy egyszerű kis programot. Felveszek egy sorozat nevű int tömböt, aminek az i. eleme (0-tól kezdődik az indexelés) kezdetben azt jelzi, hogy az i+1 szám hány mintasorozatban szerepel. A példában ez így néz ki:
1,1,2,3,3,2,2,1. A 4-es számnak megfelelő érték (3. indexű elem) 3, ami azt jelenti, hogy a 4 3 db mintasorozatban szerepel (1,3,4; 2,4,5; 4,6,7). Ezért az algoritmusnak megfelelően az első kihúzandó szám a 4 lesz. Az 5 is 3 mintasorozatban szerepel, azonban a 4 előbb van, ezért azt választjuk. Ezzel máris elrontottuk a felsorolt 3 mintasorozatot, a továbbiakban ezeket nem vesszük figyelembe. Most a sorozat tömb elemeit csökkenteni fogjuk, annak megfelelően, hogy az egyes számok a még megmaradt mintasorozatok közül hányban szerepelnek. Ezt az eljárást egészen addig ismételjük, amíg a sorozat tömb minden eleme 0 nem lesz.
A programkód:
#include <Windows.h>
#include <stdio.h>
int main(int argc,char *argv[])
{
if(argc<3){
printf("Hasznalata: mintat_gyomlal <a gyomlalando sorozat hossza> <minta elemek 1... novekvoleg>");
exit(1);
}
int mintahossz=argc-2,sorozathossz=atoi(argv[1]);
auto minta=new int[mintahossz];
for(int i=0;i<mintahossz;++i){
minta[i]=atoi(argv[i+2]);
}
int minta_terjedelem=minta[mintahossz-1];
auto sorozat=new int[sorozathossz];
for(int i=0;i<sorozathossz;++i){
sorozat[i]=0;
}
for(int i=0;i<=sorozathossz-minta_terjedelem;++i){
for(int j=0;j<mintahossz;++j){
++sorozat[minta[j]+i-1]; //a tomb kezdeti feltotlese. az i.-edik elem azt jelzi, hogy az i+1 szam hany mintasorozatban szerepel
}
}
printf("A sorozatbol kihuzando szamok: ");
while(1){
int kihuzando,max=0;
//megkeressuk az elso, legtobb mintasorozatban szereplo szamot, ez lesz a kihuzando+1 (a kihuzando indexu, mivel 0-val kezdodik az indexeles)
for(int i=0;i<sorozathossz;++i){
if(sorozat[i]>max){
kihuzando=i;
max=sorozat[i];
}
}
if(max==0)break;
printf("%d ",kihuzando+1);
//A kihuzott szam utan a sorozat tomb elemeit csokkentjuk, hogy tovabbra is azt jelezze, a megmaradt ep mintasorozzatok kozul hanyban szerepel az adott szam
for(int i=0;i<mintahossz;++i){
int n=kihuzando-minta[i];
for(int j=0;j<mintahossz;++j){
int k=minta[j]+n;
if(k>=0 && sorozat[k]>0){
--sorozat[k];
}
}
}
}
delete[] minta;
delete[] sorozat;
}Kissé off topic voltam, de ha már itt tetted fel a kérdést, itt válaszoltam. Nem vagyok biztos benne, hogy optimális megoldást ad az algoritmus, de biztosan mintamenteset, és szerintem közel optimálisat. Bár a mohó algoritmusok nem mindig jók. A program egyébként a példára azt fogja kiírni, hogy a 4-et és 5-öt hagyd el, ami jó és optimális is (legalább 2 elemet el kell hagyni). Mivel kezdetben N-mintaterjedelem+1 (mintaterjedelem a legnagyobb, vagyis utolsó mintaelem) mintasorozat van és egy elem kihúzásával legfeljebb nm (minta elemszáma) mintasorozatot rontunk el, ezért legalább (N-mintaterjedelem+1 )/nm felső egész része számú elem kihúzására van szükség. A példában ez 5/3=2, tehát legalább 2 elemet ki kell húzni.
-
jattila48
aktív tag
válasz
AsterixComic #3101 üzenetére
1. Ha átdefiniálod a new operátort pl. debug céljából. Ekkor magában az átdefiniálásban nem new-t, hanem malloc-ot fogsz használni.
Vagy ha egyszerűen csak szükséged van egy bizonyos méretű pufferre, ahová később olvasol be (pl. fájlból, hálózatról) adatot. Ezt lehet persze char *p=new char[meret]; -tel is, de akkor már a malloc legalább olyan jó. Vagyis akkor, ha nem konstruálni akarsz egy előre ismert típusú objektumot, hanem csak külső forrásból (fájl, hálózat) beolvasni bináris adatot, aminek a típusát esetleg nem is ismered előre. Ilyen lehet pl, ha IP csomagokat olvasol be, amikről előre nem tudod, hogy TCP vagy UDP csomagot fog-e tartalmazni. Ekkor a típus megállapítása után (IP protokoll jelzés) az IP payload részére egyszerűen egy C pointercasttal "ráhúzod" a TCP vagy UDP struktúrát. -
dobragab
addikt
válasz
EQMontoya #3112 üzenetére
Erős egyszerűsítés, szándékosan. Az eredmény végül is az, hogy a globális op new hívódik, és nem malloc. Tudod ellenőrizni, ha felüldefiniálod az op new-t.
#include <memory>
#include <vector>
#include <iostream>
#include <cstdlib>
void * operator new(size_t size)
{
std::cout << "op new!" << std::endl;
void * ptr = malloc(size);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
int main()
{
std::vector<int> vec;
vec.push_back(1);
return 0;
}És ez a nullptr kivételével szabványos C++98.
-
EQMontoya
veterán
válasz
dobragab #3111 üzenetére
std::vector tudomásom szerint nem malloc-ot hív, hanem :: operator new-t. Ez a tény mondjuk C++ alapjai vizsgán erős.
Ez így erős egyszerűsítés. Egyrészt implementációtól függ. De nézzük akkor x86-64-en.
Std::allocator-t használ ugye alapból a foglalásra.
Utána placement new-val konstruálgat.
Ha pedig törölsz belőle, és nem a végéről, akkor op=-vel pakolja az elemeket visszafelé, majd az utolsót destruálja. (pedig nem azt törölted) -
dobragab
addikt
válasz
EQMontoya #3110 üzenetére
Akár egy struct-ot is lehet malloc-kal foglalni, és utána adattagonként inicializálni, bár jobb helyeken kétszeri lefejezés jár érte.
std::vector tudomásom szerint nem malloc-ot hív, hanem ::operator new-t. Ez a tény mondjuk C++ alapjai vizsgán erős.
Szóval kezdőknek: a fő különbség, hogy a new hívhat ctort a lefoglalt memóriaterületre, míg a malloc nem. Ha nem kell ctort hívni, simán helyettesítheti, de ez általában csak alaptípusnál fordul elő. Az részletkérdés, hogy kicsit máshogy kell használni, és más a hibajelzés módja.
-
EQMontoya
veterán
-
LordX
veterán
válasz
AsterixComic #3101 üzenetére
1. Felelős munkatársak megvetése esetén, általuk való verés elszenvedésével ideiglenesen (code review-ig) helyettesithető.
2. Logikaira ki tudsz találni példát, bitenkénti és-re lásd 1-es pont. -
EQMontoya
veterán
válasz
AsterixComic #3101 üzenetére
1,
Ez egy bonyolultabb téma, kurvára nem alapokhoz való. A válasz egyébként igen, és van is létjogosultsága bizonyos esetekben. Illetve csak félig helyettesítődik ott is, mert placement new-t akkor is kell használni, de a lényeg az, hogy van, amikor szeretnénk elválasztani a memóriafoglalásokat az objektumok inicializálásától és megszüntetésétől.
Jó példa erre az vector, ami lazán fog Neked a háttérben valamekkora helyet foglalni, és oda pakolászol. -
ToMmY_hun
senior tag
válasz
AsterixComic #3101 üzenetére
2:
logikai:
if( a && b){
kifejezes;
}A kifejezés akkor és csak akkor kerül végrehajtásra, ha az "a" és a "b" értéke is logikai igaz.
bitenkénti és:
int a = 0b1010;
int b = 0b1100;c = a & b;
c értéke ekkor: 0b1000;
-
AsterixComic
csendes tag
Sziasztok!
C++ alapjai vizsgán az alábbi két kérdéssel találkoztam:
-1- Helyettesíthető-e a new operátor a malloc() eljáráshívással? Milyen esetekben és hogyan?
-2- Példákon mutassa be a logika ÉS és bitenkénti ÉS operátorok használatát.Szerintetek mi lenne a helyes válasz az elsőre és milyen példát lenne célszerű adni a másodikra?
köszönöm szépen a segítséget
Új hozzászólás Aktív témák
Hirdetés
● ha kódot szúrsz be, használd a PROGRAMKÓD formázási funkciót!
- BestBuy topik
- Honda topik
- Samsung Galaxy Watch7 - kötelező kör
- Samsung Galaxy Watch6 Classic - tekerd!
- Kuponkunyeráló
- D1Rect: Nagy "hülyétkapokazapróktól" topik
- Mobil flották
- Milyen okostelefont vegyek?
- Nvidia GPU-k jövője - amit tudni vélünk
- Telekom otthoni szolgáltatások (TV, internet, telefon)
- További aktív témák...
- 16GB-os SODIMM (notebook) DDR4 RAM bazár - nézz be, lesz, ami kell neked!
- HP 15-af105nh laptop (15,6FHD/AmdQuad/4GB/128SSD/Magyar) - Akku X
- JOYOR S5 Pro 10" Elektromos Roller 26Ah Akkumulátorral Moddolt!
- XPS 13 9310 13.4" FHD+ IPS i7-1185G7 16GB 512GB NVMe ujjlolv IR kam gar
- Megkimélt Apple iPhone 8 Plus 64GB Fekete szinben, 100% akkuval, kártyafüggetlen, garanciával
- Telefon felvásárlás!! iPhone 12 Mini/iPhone 12/iPhone 12 Pro/iPhone 12 Pro Max
- BESZÁMÍTÁS! MSI B550 R7 5700X 32GB DDR4 500GB SSD RTX 3070 8GB ZALMAN Z1 Plus Be quiet! 650W
- Bomba ár! Lenovo ThinkPad X390: i5-G8 I 16GB I 256GB SSD I 13,3" FHD Touch I Cam I W11 I Gari!
- Eredeti Lenovo 300W töltők - ADL300SDC3A
- Beszámítás! Sony PlayStation 5 825GB SSD digital konzol garanciával, hibátlan működéssel
Állásajánlatok
Cég: PC Trade Systems Kft.
Város: Szeged
Cég: CAMERA-PRO Hungary Kft
Város: Budapest