Black Friday = Pricewatch Bekijk onze selectie van de beste Black Friday-deals en voorkom een miskoop.

[C++] Operator + Wrapper

Pagina: 1
Acties:

  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Hallo,

Voor een schoolopdracht moet ik een eenvoudig programma schrijven rond een bijgelevede library die wat outputfuncties voor de console verzorgt. Dit is echter gebaseerd op windows.h; dus heb ik besloten om een identieke API te schrijven gebaseerd op ncurses.

Een probleem waar ik daarbij op stoot, is dat na elke "cout" een ncurses refresh() zou moeten gecallt worden. Het lukt echter niet goed om dit op te lossen. Heeft iemand een idee hoe ik "cout" verander zodat er een "refresh()" call gebeurt na elke output?

Zelf had ik er aan gedacht om wrapper cout functie te schrijven, die dan de echte cout callt, maar er een refresh achter plaatst. Om cout's flexibiliteit te bewaren, zou ik dus een functie moeten schrijven waarbij de operator "<<" ondersteund wordt. In principe is dit niet zo moeilijk, zeker niet via C++'s <template> systeem, maar ik vind niet hoe ik een operator aan een functie bind (voorbeelden spreken enkel van operator overloading aan class objects). Ik een klasse zou ik het volgende doen:
C++:
1
const serverLinuxTCP& serverLinuxTCP::operator << ( const std::string& s ) const

waarbij serverLinuxTCP een klasse is die ik ervoor gedefinieerd heb (code fragmentje komt uit een library die ik vroeger geschreven heb).
Is het mogelijk om een operator te binden aan een reguliere functie? En kan ik een wrapper schrijven rond de bestaande "cout" functie, en daarbij de standaard cout syntax gebruiken?

Bedankt voor alle hints qua implementatie, of hoe ik vermelde problemen met mijn eigen implementatie oplos :)
maleadt

Verwijderd

Het is mogelijk om operator << te overloaden als losse functie, maar heeft dan wel 2 argumenten nodig dan. Eerste argument staat links van de operator, 2de staat er rechts van.

Voorbeeld van zulk een functiedefinitie:
C++:
1
std::ostream& operator<<(std::ostream& os, const std::string& str);

[ Voor 13% gewijzigd door Verwijderd op 04-10-2008 22:16 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Je aanpak is wat onhandig. Op het moment dat je een ostream gaat simuleren zul je ook alle conversies zelf moeten gaan doen (of je moet iets als ostringstream gebruiken om de omzetting voor jou te doen), maar feitelijk is dat niet wat je wilt.

De C++ iostreams zijn een abstractie voor IO. Zoals je zelf al aan de functiedefinitie van evidoth ziet, accepteert een typische operator<< een std::ostream als parameter. Maar die ostream kan ondertussen wel naar de standaard output schrijven, of een file, of een memory buffer, of een socket, etc. De achterliggende implementatie wordt dan ook geregeld door een streambuffer. Door je eigen streambuf klasse te implementeren kun je gewoon de standaard streams blijven gebruiken - je kunt zelfs je eigen streambuffer in std::cout hangen zodat alle verdere output via jouw streambuf verloopt.

Ik neem aan dat je verder niet zelf de output hoeft te verzorgen, maar gewoon moet zorgen dat refresh() wordt aangeroepen? Dan is het het handigst om gewoon een streambuf klasse te deriven waarin je in de xsputn(), overflow() en sync() functies de output doorstuurt naar de originele streambuf van cout en daarna een refresh() doet.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Bedankt voor jullie reacties!

Zoals .oisyn aanraadde, ben ik van mijn eigen code afgestapt en eens naar streambuffers gaan kijken. Als eerste confrontatie ermee heeft het best wat tijd gekost om alles te snappen, maar kom het is me uiteindelijk wel gelukt :)
Ik heb er de volgende code op overgehouden:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <streambuf>

class OutputRefresh : public std::streambuf
{
    public:
        OutputRefresh(std::streambuf* wrapped) : _wrapped(wrapped)
        {
        }

    protected:
        int_type overflow(int_type ch)
        {
            if (traits_type::not_eof(ch))
                ch = _wrapped->sputc(ch);
            printf("refresh()\n");
            return ch;
        }


        int sync()
        {
            return _wrapped->pubsync();
        }

    private:
        std::streambuf* _wrapped;
};

int main()
{
    // Vervang cout's buffer met ons alternatief
    std::streambuf* cout_original = std::cout.rdbuf();
    OutputRefresh cout_new(cout_original);
    std::cout.rdbuf(&cout_new);

    // Deze cout zal via onze nieuwe buffer gaan
    std::cout << "Hello world!\n";

    // Herstel cout's buffer
    std::cout.rdbuf(cout_original);
}

Het mag dan niet al te optimaal zijn, maar goed ze werkt, dat is al iets :)

Tot hiertoe de dingen die werken :P Bij het includen van de library (hier "scherm.h"), initialiseer ik een object genaamd "nCurses". Dit doe ik zodat ik een routine heb die automatisch gecallt wordt bij het afsluiten van het programma (namelijk de destructor van het object, waarin ik wat ncurses cleanup routines plaats).

Nu wou ik in dezelfde klasse "nCurses" de cout redirectie implementeren. Dit zorgt echter voor problemen.
De klasse ziet er als volgt uit:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class nCurses
{
    public:
        nCurses();
        ~nCurses();
    private:    
        streambuf* cout_original;
};
nCurses::nCurses()
{
    // Enter nCurses mode
    initscr();
    
    // replace cout stream buffer
    cout_original = cout.rdbuf();
    OutputRefresh cout_new(cout_original);
    cout.rdbuf(&cout_new);
}

nCurses::~nCurses()
{
    // Exit nCurses mode
    endwin();
    
    // restore cout stream buffer
    cout.rdbuf(cout_original);
}


De stukjes code wat betreft cout-redirectie zijn identiek dezelfde als in het eerste codefragment. Enigste verschil is dat ze hier hun werk niet doen :P Het draaien van de executable resulteert in een vage segmentatiefout.

Valgrind leert me het volgende:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
==7498== Invalid read of size 4
==7498==    at 0x40F3087: std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, int) (in /usr/lib/libstdc++.so.6.0.10)
==7498==    by 0x40F325B: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.10)
==7498==    by 0x8049316: main (test.cpp:9)
==7498==  Address 0xbea633bc is just below the stack ptr.  To suppress, use: --workaround-gcc296-bugs=yes
==7498== 
==7498== Jump to the invalid address stated on the next line
==7498==    at 0x8B000001: ???
==7498==    by 0x40F325B: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.10)
==7498==    by 0x8049316: main (test.cpp:9)
==7498==  Address 0x8b000001 is not stack'd, malloc'd or (recently) free'd
==7498== 
==7498== Process terminating with default action of signal 11 (SIGSEGV)
==7498==  Access not within mapped region at address 0x8B000001
==7498==    at 0x8B000001: ???
==7498==    by 0x40F325B: std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*) (in /usr/lib/libstdc++.so.6.0.10)
==7498==    by 0x8049316: main (test.cpp:9)

waarbij regel 9 een ordinaire "cout" is in mijn main loop (die dus inderdaad geredirect zou moeten zijn). Schakel ik redirectie uit, draait het programma perfect...

Kan iemand me een hint geven in de goede richting? Ik zoek er nu al een tijdje op, maar dergelijke vage errors leveren niet veel resultaten op. Alvast bedankt!
maleadt

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Weet je zeker dat std::cout al bestaat als jij nCurses contruct? Als het allebei globale statics zijn bijvoorbeeld, dan is de ordering van constructie ongedefinieerd.

  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Ja, cout is gedefiniëerd. Een cout plaatsen voor initscr() resulteert in correcte output voor de segmentatiefout.

Ik wist ook niet goed of ik cout_new (het object dat cout's buffer gaat vervangen) moest definiêren als private van de nCurses klasse, net zoals ik bij cout_original gedaan heb. Misschien veroorzaakt dit een invalid read?

EDIT
Ik heb het al gevonden, zoals ik zei instantieerde ik een object van de nCurses klasse in mijn "sherm.h", opdat ik via inclusion een initscr krijg, en bij afsluiten een endwin. Maar deze code staat natuurlijk niet in de main() loop, wat deze invalid read opleverde...

EDIT2
Als ik de initialisatie en clean-up code die ik nu in de nCurses klasse uitvoerde, migreer naar mijn main() loop, werkt alles perfect. Is er een mogelijkheid om via compiler instructies oid code aan main te prependen en appenden? Geen propere oplossing, I know O-)

[ Voor 47% gewijzigd door maleadt op 05-10-2008 13:13 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MALEADt schreef op zondag 05 oktober 2008 @ 13:00:
EDIT
Ik heb het al gevonden, zoals ik zei instantieerde ik een object van de nCurses klasse in mijn "sherm.h", opdat ik via inclusion een initscr krijg, en bij afsluiten een endwin. Maar deze code staat natuurlijk niet in de main() loop, wat deze invalid read opleverde...

EDIT2
Als ik de initialisatie en clean-up code die ik nu in de nCurses klasse uitvoerde, migreer naar mijn main() loop, werkt alles perfect. Is er een mogelijkheid om via compiler instructies oid code aan main te prependen en appenden? Geen propere oplossing, I know O-)
Volgens mij is dat precies wat ik bedoelde :) Ik neem aan dat je in je "scherm.h" een of andere "static nCurses the_nCurses;" defineerde? Op zich kan dat prima buiten je main() loop, maar het probleem is dat je geen garantie hebt wat er eerder wordt constructed (en destructed!): std::cout, of jouw static nCurses. Het maakt niet uit welke eerder of later in de source voorkomt, dus #includes omdraaien oid helpt niet. Zo'n probleem heb je ook met singleton classes, en daar is de oplossing meestal dat de singleton pas constructed wordt als hij gebruikt wordt (en opnieuw constructed wordt als hij gebruikt wordt en als dectructed was om dtor problemen te ontlopen; phoenix singleton). Probleem hier dat je met cout te maken hebt die je niet aan kan passen, dus ik denk dat je dit nooit helemaal goed krijgt. In ieder geval niet zonder allemaal trucks en hacks. ik zou gewoon aan het begin van main() een nCurses constructen, dan is alles opgelost: std::cout bestaat bij ctor en ook nog bij dtor. Dat is ook netter. Het is irritant als de inclusie van een header allemaal dingen veranderd zonder dat je dat merkt. Misschien wil ik wel op een gegeven moment ncurses uitzetten. Hoe doe ik dat dan als het allemaal automatisch in de header gebeurt?

[ Voor 14% gewijzigd door Zoijar op 05-10-2008 13:41 ]


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Bedankt, ik ga het inderdaad op die manier proberen :)

Blijft er echter wel nog 1 klein probleem over, nu ik de relevante code opnieuw naar de nCurses klasse verhuisd heb, schort er iets met de syntax die ik gebruik om een private object inhoud te geven. Ik denk dat ik het object overschrijf, waardoor de data verdwijnt van zodra de constructor afgelopen is.
Wat code verduidelijk het allemaal:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class nCurses
{
    public:
        nCurses();
        ~nCurses();
    private:    
        streambuf* cout_original;
        OutputRefresh cout_new(streambuf*);
};
nCurses::nCurses()
{
    // Magic INIT code
    cout << "INIT\n";
    initscr();
    cout_original = cout.rdbuf();
    OutputRefresh cout_new(cout_original);
    cout.rdbuf(&cout_new);
}


Het bleek dat ik cout_new ook als private moest definiëren, of alle data ging verloren van zodra de constructor zijn werk gedaan had. Nu ik die declaratie toegevoegd heb, meen ik ook mijn initialisatie te moeten aanpassen:
C++:
1
OutputRefresh cout_new(cout_original);


Klopt het dat in huidige opzet de data van cout_new verloren gaat zodra de constructor afgelopen is? Zoja, hoe moet ik mijn syntax aanpassen :$ ik heb geprobeerd
C++:
1
2
3
cout_new = OutputRefresh(cout_original);
cout_new = new(cout_original)
cout_new = OutputRefresh::OutputRefresh(cout_original);

maar deze werken allemaal niet.

Vergeef me voor deze misschien makkelijke vraag, maar dergelijke problemen kom je nu eenmaal tegen als je een taal op je eigen leert. Toch eens een goed boek kopen :+

EDIT
en idd, ff getest met een integer, de inhoud verdwijnt als ik in de constructor ook "int foobar = 5" gebruikt. Nu nog de juiste syntax vinden om cout_new niet te herdefiniëren maar enkel data toe te wijzen

[ Voor 6% gewijzigd door maleadt op 05-10-2008 14:11 ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MALEADt schreef op zondag 05 oktober 2008 @ 13:57:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class nCurses
{
    public:
        nCurses();
        ~nCurses();
    private:    
        streambuf* cout_original;
        OutputRefresh cout_new(streambuf*);
};
nCurses::nCurses()
{
    // Magic INIT code
    cout << "INIT\n";
    initscr();
    cout_original = cout.rdbuf();
    OutputRefresh cout_new(cout_original);
    cout.rdbuf(&cout_new);
}


Het bleek dat ik cout_new ook als private moest definiëren, of alle data ging verloren van zodra de constructor zijn werk gedaan had. Nu ik die declaratie toegevoegd heb, meen ik ook mijn initialisatie te moeten aanpassen:
C++:
1
OutputRefresh cout_new(cout_original);


Klopt het dat in huidige opzet de data van cout_new verloren gaat zodra de constructor afgelopen is? Zoja, hoe moet ik mijn syntax aanpassen :$
Die code klopt volgens mij niet (pakt je compiler dat??)

Je maakt eerst een object OutputRefresh aan in je class scope, dat gebeurt automatisch voor je ctor wordt uitgevoerd. Dan maak je een local OutputRefresh aan in de ctor scope, die wordt gewoon gewist na beindiging van je ctor, en die andere blijft ongeinitialiseerd (alleen contrustced)

volgens mij kan je dit doen:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class nCurses
{
    public:
        nCurses();
        ~nCurses();
    private:    
        streambuf* cout_original;
        OutputRefresh cout_new;
};

// initializer list for cout_new
nCurses::nCurses() : cout_new(cout.rdbuf())
{
    // Magic INIT code
    cout << "INIT\n";
    initscr();
    cout.rdbuf(&cout_new);
}


Dan mis je alleen de oude, maar dat moet je maar oplossen door die op te slaan in OutputRefresh oid. Je kan ook OutputRefresh een lege ctor geven, en een init() member. Dan kan het op je oude manier, en dan cout_new.init(cout.rdbuf()) aan te roepen. Zoiets.

  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
Je maakt eerst een object OutputRefresh aan in je class scope, dat gebeurt automatisch voor je ctor wordt uitgevoerd. Dan maak je een local OutputRefresh aan in de ctor scope, die wordt gewoon gewist na beindiging van je ctor, en die andere blijft ongeinitialiseerd (alleen contrustced)
Exacte beschrijving van wat ik vermoedde dat mijn probleem was! toch wel vreemd dat gcc geen enkel probleem had bij die constructie.

Anyway; bedankt om de correcte syntax te tonen (werkt inderdaad perfect). Nu nog eens uitvogelen hoe alles exact in zijn werk gaat zodat ik een volgende keer niet tegen gelijkaardig probleem aanloop. :)

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Zoijar schreef op zondag 05 oktober 2008 @ 12:54:
Weet je zeker dat std::cout al bestaat als jij nCurses contruct? Als het allebei globale statics zijn bijvoorbeeld, dan is de ordering van constructie ongedefinieerd.
Dat is met linker hinting te corrigeren of met creatief programmeren. Linker hints zijn compilerspecifiek overigens, zoals bij MSVC++ met #pragma init_seg. Voor GCC weet ik het zo snel niet.

Professionele website nodig?


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

curry684 schreef op zondag 05 oktober 2008 @ 15:31:
Dat is met linker hinting te corrigeren of met creatief programmeren. Linker hints zijn compilerspecifiek overigens, zoals bij MSVC++ met #pragma init_seg. Voor GCC weet ik het zo snel niet.
Ja, ok, maar wat daar wordt uigelegd, bv het "Construct On First Use Idiom", dat zijn singletons waar ik het eerder over had. Het is enigszins lastig omdat je een standaard std::cout wilt gebruiken en die kan je niet makkelijk even zelf constructen. Althans, het kan wel, maar dan kunnen gebruikers niet std::cout gebruiken. Bestaande software moet dan aangepast worden. Of je moet heel moeilijk gaan doen met alles zelf initialiseren met singeltons, en dan helemaal aan het einde over de default std::cout heen kopieren. Dat zou wel kunnen. Singletons en hun issues zijn vele hoofdstukken in boeken over geschreven, bv. modern C++ design, design patterns en pattern hatching. #pragma linker hints die je programma kunnen laten crashen als ze niet supported zijn zou ik nooit aan beginnen.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 06-09 00:37

curry684

left part of the evil twins

Persoonlijk vind ik pragma linker hinting een acceptabele workaround voor een fundamentele tekortkoming van C++. Zoals met alle pragma's dien je wel fatsoenlijke compiler checks in te bouwen als je multiplatform werkt, maar zo werken pragmas nu eenmaal.

Professionele website nodig?


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zeker weten dat cout e.d. zijn geconstruct kan gewoon op een standaard C++ manier. 't Is gewoon een kwestie van een ios_base::Init constructen, en daarna kun je veilig de standaard streams gebruiken.

C++:
1
2
basic_ios::Init initStdStreams;
MyClass someObjectThatUsesCoutInCtor;

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op zondag 05 oktober 2008 @ 20:10:
Zeker weten dat cout e.d. zijn geconstruct kan gewoon op een standaard C++ manier. 't Is gewoon een kwestie van een ios_base::Init constructen, en daarna kun je veilig de standaard streams gebruiken.

C++:
1
2
basic_ios::Init initStdStreams;
MyClass someObjectThatUsesCoutInCtor;
Vaag. Waar staat dat dan? Dus basic_oios::Init is een special case die appart gechecked wordt bij globale intialisaties?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

basic_ios::Init zorgt er simpelweg voor dat de default streams gecontruct worden als ze dat nog niet zijn. Niets special case aan dus, en omdat je 'm per definitie construct voor je eigen objects in dezelfde TU door het ding bovenaan te zetten, weet je dus zeker dat je cout kunt gebruiken.

27.4.2.1.6
1 The class Init describes an object whose construction ensures the construction of the eight objects declared in <iostream> (27.3) that associate file stream buffers with the standard C streams provided for by the functions declared in <cstdio> (27.8.2).

2 For the sake of exposition, the maintained data is presented here as:
— static int init_cnt, counts the number of constructor and destructor calls for class Init, initialized to zero.

3 Init();
Effects: Constructs an object of class Init. If init_cnt is zero, the function stores the value one in init_cnt, then constructs and initializes the objects cin, cout, cerr, clog (27.3.1), wcin, wcout, wcerr, and wclog (27.3.2). In any case, the function then adds one to the value stored in init_cnt.

4 ~Init()
Effects: Destroys an object of class Init. The function subtracts one from the value stored in init_cnt and, if the resulting stored value is one, calls cout.flush(), cerr.flush(), clog.flush(), wcout.flush(), wcerr.flush(), wclog.flush().

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op maandag 06 oktober 2008 @ 13:03:
basic_ios::Init zorgt er simpelweg voor dat de default streams gecontruct worden als ze dat nog niet zijn. Niets special case aan dus, en omdat je 'm per definitie construct voor je eigen objects in dezelfde TU door het ding bovenaan te zetten, weet je dus zeker dat je cout kunt gebruiken.

27.4.2.1.6

[...]
Oh, de volgorde is wel gegarandeerd binnen dezelfde TU? Dat wist ik niet; ik dacht dat het altijd undefined was. Niettemin kan je dan Init contructen in de ctor van je eigen class. Kende de class niet.

(Buiten het feit dat het wel mogelijk is dan, vind ik het nog steeds mooier om hier alleen je nCurses wrapper te gebruiken voor de lifetime/scope van een ncurses object dat je zelf construct: niet een static in een geinclude header voor program lifetime.)

[ Voor 17% gewijzigd door Zoijar op 06-10-2008 13:51 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar schreef op maandag 06 oktober 2008 @ 13:50:
[...]

Oh, de volgorde is wel gegarandeerd binnen dezelfde TU? Dat wist ik niet; ik dacht dat het altijd undefined was.
Dat zou dan wel heel erg onwerkbaar zijn :). Globale objecten worden altijd geconstruct in de volgorde van definitie binnen dezelfde TU, en alle globaal geconstructe objecten (inclusief local statics) worden ook in de omgekeerde volgorde gedestruct als dat ze zijn geconstruct.
Niettemin kan je dan Init contructen in de ctor van je eigen class. Kende de class niet.
Dat vond ik niet mooi. Dan kun je wel een Init gaan constructen in élke class die cout gebruikt in z'n ctor, omdat je 'm eventueel kunt constructen voor main(). Ik vind dat niet de verantwoordelijkheid voor de klasse. Een uitzondering hierop is als het doel van de klasse is dat hij geconstruct wordt voor main(), zoals bijv. bij een singleton of idd hier met z'n nCurses.
(Buiten het feit dat het wel mogelijk is dan, vind ik het nog steeds mooier om hier alleen je nCurses wrapper te gebruiken voor de lifetime/scope van een ncurses object dat je zelf construct: niet een static in een geinclude header voor program lifetime.)
Eens :)
MALEADt schreef op zondag 05 oktober 2008 @ 13:57:
Klopt het dat in huidige opzet de data van cout_new verloren gaat zodra de constructor afgelopen is?
Ja natuurlijk klopt dat. Je maakt het cout_new object op de stack. Als je 'm wilt behouden na de ctor (en dat wil je, want cout heeft een pointer naar het object), moet je 'm globaal aanmaken (of als static in de functie), of je moet 'm op de heap aanmaken. Als je 'm new't moet cout_new natuurlijk wel een pointer zijn, en als je netjes wilt zijn moet je 'm aan het eind ook zelf destructen (in de destructor van je nCurses bijv.).

[ Voor 53% gewijzigd door .oisyn op 06-10-2008 14:28 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
(Buiten het feit dat het wel mogelijk is dan, vind ik het nog steeds mooier om hier alleen je nCurses wrapper te gebruiken voor de lifetime/scope van een ncurses object dat je zelf construct: niet een static in een geinclude header voor program lifetime.)
Very true, maar mijn opzet hier is om een identieke API te schrijven die zonder enige wijzigingen van code toch perfect werkt. Een aangezien de windows code geen extra modesetting vereist, ga ik het afhandelen van de nCurses modus toch via een static oplossen in mijn header code.

Los daarvan is het wel jammer dat een dergelijke header door een student geschreven moet worden, en niet door de school zelf voorzien is (anno 2008 is dat voor een informatica-georienteerde richting toch zo geen vreemde eis). Daarnaast zou het geheel veel makkelijker zijn als de API in eerste opzet platform-onafhankelijk zou moeten zijn, een API voor platform B schrijven terwijl de oorspronkelijke API voor platform A gemaakt is blijkt een pak moeilijker te zijn.

Nuja, het is wel een leuke vingeroefening, die me reeds veel bijgeleerd heeft :)

  • writser
  • Registratie: Mei 2000
  • Laatst online: 13-11 10:55
Los daarvan is het wel jammer dat een dergelijke header door een student geschreven moet worden, en niet door de school zelf voorzien is (anno 2008 is dat voor een informatica-georienteerde richting toch zo geen vreemde eis).
Kon je het niet in Windows doen?

Onvoorstelbaar!


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
writser schreef op dinsdag 07 oktober 2008 @ 21:25:
Kon je het niet in Windows doen?
En wat voor een oplossing is dat dan :X Telkens ik een oefening voor dit vak moet maken (want het zijn veelgebruikte libraries), wordt ik verondersteld om alle andere activiteiten stop te zetten en speciaal te rebooten in een OS dat mij niet ligt?
Ik zou er geen problemen met gehad hebben moest het een eenmalige opdracht betreffen voor een bijvak (pak nu informatica in het secundair), maar ik vind het niet gepast in een informaticagerichte richting - waar Linux nota bene al sterk in het leerprogramma geintegreerd is!

Nuja, het zal natuurlijk maar een probleem vormen voor een minderheid van de studenten, maar het lijkt me niet de beste ingesteldheid die software developers in spe mee zouden moeten krijgen :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

MALEADt schreef op dinsdag 07 oktober 2008 @ 20:49:
Een aangezien de windows code geen extra modesetting vereist, ga ik het afhandelen van de nCurses modus toch via een static oplossen in mijn header code.
Echter is je argument onzin, aangezien je ook gewoon een static in je ncurses.cpp kunt plaatsen en dan werkt het net zo goed. Als je het als static in de header zet wil dat zeggen dat elke translation unit (source file) die je header include zijn eigen versie van het ncurses object krijgt, waardoor de cout dus effectief meerdere malen gewrapped wordt.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • writser
  • Registratie: Mei 2000
  • Laatst online: 13-11 10:55
Telkens ik een oefening voor dit vak moet maken (want het zijn veelgebruikte libraries), wordt ik verondersteld om alle andere activiteiten stop te zetten en speciaal te rebooten in een OS dat mij niet ligt?
Tja, je kan je ook gewoon even wat soepeler opstellen: af en toe even in Windows werken is geen ramp. En dat was waarschijnlijk een stuk minder werk dan alles herschrijven naar ncurses. Remember: een goede programmeur is lui! (of maak je dit voor je school?)
Nuja, het zal natuurlijk maar een probleem vormen voor een minderheid van de studenten, maar het lijkt me niet de beste ingesteldheid die software developers in spe mee zouden moeten krijgen :)
Jij gaat later als software developer bij Accenture of Logica alle software waar je aan moet gaan werken eerst platform-onafhankelijk maken? Succes. :P

[ Voor 9% gewijzigd door writser op 08-10-2008 00:17 ]

Onvoorstelbaar!


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 15-11 15:54
Relax, de TS is student en aan het uitvogelen hoe het een en ander werkt, daar is nog nooit iemand dommer van geworden ( En ik ook niet want ik heb geleerd dat er een speciaal init object is voor de standaard iostreams ); en een gezond portie eigenwijsheid kan hem daarbij nog behoorlijk veel verder helpen.

Btw er zijn ook mensen die voor geen goud bij dat soort toko's willen werken. :P

[ Voor 12% gewijzigd door farlane op 08-10-2008 08:44 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • writser
  • Registratie: Mei 2000
  • Laatst online: 13-11 10:55
Tuurlijk is het mooi en leerzaam om wat te experimenteren. Meestal leuker dan de opdrachten maken ;). Maar ik vind het een beetje flauw om je school af te kraken omdat ze voor een vak geen platform-onafhankelijke code aanbieden. Soms gaat een vak uit van Linux, soms van Windows, tja, dan moet je je ff aanpassen. Net de echte wereld. Ga in elk geval niet de opdrachtgever afkraken als je besluit alles te porten naar een ander platform .. :P

Maar goed, dit gaat off-topic. De discussie over iostreams was wel erg leerzaam.

Onvoorstelbaar!


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
writser schreef op woensdag 08 oktober 2008 @ 00:15:
Tja, je kan je ook gewoon even wat soepeler opstellen: af en toe even in Windows werken is geen ramp.
Waar leid je ui af dat ik daar een probleem mee heb? Het gebeurt af en toe dat ik wel moet van OS switchen om een bepaalde opdracht te maken, maar ik heb er inderdaad problemen mee als dat zou moeten doen voor een groot deel van de opdrachten van een hoofdvak.
En mijn school afkraken doe ik evenmin, ik heb er alleen kritiek op, wat naar mijn weten geen kwaad kan.

Maar goed, in eerste instantie ben ik hieraan begonnen om iets bij te leren en eens te weten hoe het is om zo goed mogelijk een API te klonen. Wat ook gelukt is, bedankt voor de reacties! :)

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 14-11 23:57

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ga je nou nog die static in de header weghalen? :)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • maleadt
  • Registratie: Januari 2006
  • Laatst online: 05-11 22:08
.oisyn schreef op woensdag 08 oktober 2008 @ 13:49:
Ga je nou nog die static in de header weghalen? :)
:$
Done

Enige vervelende nu is dat het geheel niet meer zo eenvoudig compilet ("g++ bron.cpp -o bron -lncurses"), en ik een project/makefile nodig heb om de output library te compilen en correct te linken...

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

MALEADt schreef op woensdag 08 oktober 2008 @ 14:34:
Enige vervelende nu is dat het geheel niet meer zo eenvoudig compilet ("g++ bron.cpp -o bron -lncurses"), en ik een project/makefile nodig heb om de output library te compilen en correct te linken...
"make" is makkelijker dan "g++ bron.cpp -o bron -lncurses"" hoor ;) Zeker volgend jaar, als je je ineens afvraagt waar die linker errors vandaan komen...

[ Voor 10% gewijzigd door Zoijar op 08-10-2008 14:47 ]

Pagina: 1