[C++] Include Hell

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Wie kent het niet? Je wijzigt een enkele header file en prompt wordt het halve project gerebuild.
Met forward declarations en minder includes in header files is hier iets aan te doen, maar echt makkelijk is dat niet. Vandaar mijn vragen.
Zijn er (gratis) tools om deze onnodige includes te detecteren?
Hoe pakken anderen dit aan?
Waarom is een forward declaratie niet altijd genoeg?
Op een gegeven moment heeft de compiler de layout en grootte van A nodig, maar dat is (IMO) niet per se tijdens de definitie van B.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A;

class B
{
  A a; // error C2079: 'B::a' uses undefined class 'A'
};

class A
{
};

int main()
{
  B;
}

Acties:
  • 0 Henk 'm!

Verwijderd

Dependencies aanpassen misschien?

Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Je kan met CMake e.d. natuurlijk bepaalde global includes segmenteren per projectonderdeel, zodat wijzigingen minder impact hebben.

Verder moet je er goed op letten dat je geen wazige API's hebt met allemaal kruisverbanden. Een veilige methode vind ik altijd om 1 soort controller class te maken die je dan verschillende objecten laat beheren. En zorg er dan vooral voor dat je vanuit die controller class referenties maakt.

En zonder header files heb je imo niet echt een goed praktijkvoorbeeld.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Wanneer je B definieert moet de compiler kunnen vaststellen wat de grootte van B is (immers, vanaf dat moment kan je sizeof( B ) gebruiken) In jouw geval is daar natuurlijk ook de definitie van A voor nodig, omdat in B een A zit.

Wat je wel kan doen is ipv een instantie van A in B te doen, een pointer naar een A in B doen. Immers de grootte van een pointer naar een object is altijd hetzelfde, en dus niet afhankelijk van de definitie van A. Dan zal ook de genoemde compile-error weg gaan :)

Gevolg: je headerfile van B is niet meer afhankelijk van die van A, dus als je A verandert, hoeft niet alles afhankelijk van B ook herbouwd te worden. Als je niet overbodig aan het includen bent, kan dat veel schelen, afhankelijk van hoe je project in elkaar steekt.

Ook kan het intressant zijn om een PCH te regelen voor stabiele headers (die dus niet veranderen, en niet afhankelijk zijn van header files die veranderen), dat kan compile-tijd flink verkorten. Moet je even de documentatie van je compiler/IDE doorzoeken hoe dat zit voor jou.

Sidenote:
Je moet wel rekening houden met de new/delete van je instantie van A, maar in het simpele geval (zelfde levensduur als B ) is het niet ingewikkeld om dat RAII te doen.
Bijvoorbeeld:
C++:
1
2
B::B() : a(new A()) { }
B::~B() { delete a; }

Disclaimer, je hebt natuurlijk wel een A op de heap staan nu, met alle mogelijke fouten die dat kan opleveren (OOM -> exception), en performance implicaties van dien (allocaties van heap zijn niet gratis, en indirectie ook niet). Alignment via __declspec(align)/ __attribute__((align)) werkt niet op de heap. YMMV

[ Voor 23% gewijzigd door MLM op 16-02-2011 13:36 ]

-niks-


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:27:
Wanneer je B definieert moet de compiler kunnen vaststellen wat de grootte van B is (immers, vanaf dat moment kan je sizeof( B ) gebruiken) In jouw geval is daar natuurlijk ook de definitie van A voor nodig, omdat in B een A zit.
Er zit een groot gat tussen de definitie van B en een gebruik van B waarbij de layout nodig is.

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op woensdag 16 februari 2011 @ 13:29:
[...]

Er zit een groot gat tussen de definitie van B en een gebruik van B waarbij de layout nodig is.
True, maar dat weet de compiler niet.
Voor hetzelfde geld doe jij:
code:
1
2
3
4
5
class B
{
  A a;
};
enum { dummy = sizeof(B) };


De compiler loopt je code regel voor regel door, hij kijk niet naar voren om te zien wat jij gaat doen verderop in de file :)

Daarvoor is forward declaration uitgevonden, dan zeg je "er bestaat een A" maar specificeer je geen layout. Dan kun je overal A gebruiken, zolang de layout niet nodig is. Wanneer je een A instantie in B stopt, is de layout nodig, en gaat de compiler dan dus ook "dat kan niet", want A is wel declared (typenaam gereserveer*), maar niet defined (layout beschreven*), dat is dus ook exact wat de compiler zegt :)

*: Het ligt natuurlijk iets complexer dan dat, maar voor dit geval gaat het op

[ Voor 33% gewijzigd door MLM op 16-02-2011 13:39 ]

-niks-


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:33:
De compiler loopt je code regel voor regel door, hij kijk niet naar voren om te zien wat jij gaat doen verderop in de file :)
Dat is toch ook niet nodig? Waar jij sizeof aanroept moet de definitie compleet zijn eerder niet. Het lijkt eigenlijk vrij simpel.

Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op woensdag 16 februari 2011 @ 13:36:
[...]

Dat is toch ook niet nodig? Waar jij sizeof aanroept moet de definitie compleet zijn eerder niet. Het lijkt eigenlijk vrij simpel.
Ah, theoretisch gezien heb je gelijk. Echter, de C++ standaard stelt aldus:
quote: ISO/IEC 14882, 3.1.6
A program is ill-formed if the definition of any object gives the object an incomplete type
Jij defined een B met een incomplete A, en is B dus ook incompleet, en dus is dat een "overtreding". Een pointer naar A is echter niet incompleet, dus die kan je wel gebruiken (dat is ook waarvoor je dus forward declarations gebruikt in de meeste gevallen).

Wil jij graag dat dit gaat werken, moet je even het C++ standards committee gaan bellen denk ik :)

[ Voor 15% gewijzigd door MLM op 16-02-2011 13:51 ]

-niks-


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:46:
Wil jij graag dat dit gaat werken, moet je even het C++ standards committee gaan bellen denk ik :)
Heb je het telefoonnummer? :p
Die zijn ook niet dom, dus ik verwacht dat er een goede reden is. Vandaar dit topic. Zeker voor grote projecten is dit toch een reeël probleem.

[ Voor 8% gewijzigd door Olaf van der Spek op 16-02-2011 13:50 ]


Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

De reden is heel simpel: als je aannames gaat doen en uitzonderingen gaat maken dan zou de compiler vrij inconsistent kunnen worden.

Je wil gewoon zeker weten dat van de objecten (op natuurlijk pointers na) compleet zijn.

Sowieso vind ik C++ niet echt subtiel in zijn foutdetectie en intelligentie maar er zijn wel meer talen die dat niet hebben.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op woensdag 16 februari 2011 @ 13:49:
[...]

Heb je het telefoonnummer? :p
Die zijn ook niet dom, dus ik verwacht dat er een goede reden is. Vandaar dit topic. Zeker voor grote projecten is dit toch een reeël probleem.
Ik DENK dat het niet mag omdat het dan een stuk moeilijker word om C++ te parsen, immers je moet dan de definitie van B gaan "bekijken" bij het eerste punt waar het gebruikt word als compleet type. Maar wat dan als je B nodig hebt om A te evalueren?
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class A;
class B;

class A
{
  B b;
};

class B
{
  A a;
};

int main()
{
  B b; //eerste gebruik van B als compleet type
}


Maar wat jij wilt kan wel, met templates:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class A;

template<typename T> 
class B_template
{ 
  T a; 
};
typedef B_template<A> B;

class A
{
  int foo;
};

int main()
{
  B bar; //template instantiation is pas hier!
}


Maar of dat daadwerkelijk jouw header-probleem gaat oplossen weet ik niet. In dit specifieke geval kan het, omdat A pas compleet hoeft te zijn als je instantieert, maar in complexere projecten heb je iets sneller een instantiation nodig waarschijnlijk ;) En ik betwijfel of dit nou bevorderlijk is voor je compile-tijd, weet ik niet ;)

[ Voor 18% gewijzigd door MLM op 16-02-2011 14:05 ]

-niks-


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:59:
Maar wat dan als je B nodig hebt om A te evalueren?
Infinite recursion, dat werkt natuurlijk nooit.
Maar of dat daadwerkelijk jouw header-probleem gaat oplossen weet ik niet. In dit specifieke geval kan het, omdat A pas compleet hoeft te zijn als je instantieert, maar in complexere projecten heb je iets sneller een instantiation nodig waarschijnlijk ;) En ik betwijfel of dit nou bevorderlijk is voor je compile-tijd, weet ik niet ;)
Dat lijkt me ook niet de juiste oplossing.

[ Voor 17% gewijzigd door Olaf van der Spek op 16-02-2011 14:12 ]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
MLM schreef op woensdag 16 februari 2011 @ 13:27:
Wanneer je B definieert moet de compiler kunnen vaststellen wat de grootte van B is (immers, vanaf dat moment kan je sizeof( B ) gebruiken) In jouw geval is daar natuurlijk ook de definitie van A voor nodig, omdat in B een A zit.

Wat je wel kan doen is ipv een instantie van A in B te doen, een pointer naar een A in B doen. Immers de grootte van een pointer naar een object is altijd hetzelfde, en dus niet afhankelijk van de definitie van A. Dan zal ook de genoemde compile-error weg gaan :)

Gevolg: je headerfile van B is niet meer afhankelijk van die van A, dus als je A verandert, hoeft niet alles afhankelijk van B ook herbouwd te worden. Als je niet overbodig aan het includen bent, kan dat veel schelen, afhankelijk van hoe je project in elkaar steekt.

Ook kan het intressant zijn om een PCH te regelen voor stabiele headers (die dus niet veranderen, en niet afhankelijk zijn van header files die veranderen), dat kan compile-tijd flink verkorten. Moet je even de documentatie van je compiler/IDE doorzoeken hoe dat zit voor jou.

Sidenote:
Je moet wel rekening houden met de new/delete van je instantie van A, maar in het simpele geval (zelfde levensduur als B ) is het niet ingewikkeld om dat RAII te doen.
Bijvoorbeeld:
C++:
1
2
B::B() : a(new A()) { }
B::~B() { delete a; }

Disclaimer, je hebt natuurlijk wel een A op de heap staan nu, met alle mogelijke fouten die dat kan opleveren (OOM -> exception), en performance implicaties van dien (allocaties van heap zijn niet gratis, en indirectie ook niet). Alignment via __declspec(align)/ __attribute__((align)) werkt niet op de heap. YMMV
Als je geen dynamisch geheugen wil gebruiken kan je ook gewoon een reference gebruiken. Je moet er alleen wel voor zorgen dat je die initialiseert in een initialiser list.

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

NC83 schreef op woensdag 16 februari 2011 @ 17:31:
[...]


Als je geen dynamisch geheugen wil gebruiken kan je ook gewoon een reference gebruiken. Je moet er alleen wel voor zorgen dat je die initialiseert in een initialiser list.
Ehm, nee. Met een reference compiled het ook, maar als je je reference initialiseerd, zal je toch naar dynamisch geheugen moeten, want je gaat die reference moeten initialiseren met een object :)
C++:
1
2
3
4
5
6
7
class A;
class B
{
  A &a; //compiled wel, reference is ook gewoon een "pointer" onder de syntactische suiker, dus compleet type
  B() : a(A()) {} //instantie gaat direct uit scope -> undefined behavior
  B() : a(*new A()) {} //A in dynamisch geheugen, moet je een reference gaan opruimen (onintuitief), en is het gewoon een "hidden" pointer
};


Wat wel voordeel van de reference is, is dat je de code in B verder niet hoeft aan te passen, omdat a.x nog steeds een geldige expressie is (met een pointer moet je a->x schrijven), maar een destructor met "delete &a" is nogal ongebruikelijk, zet het ieg wel in de comments erbij :P

On topic, wat de TS wilt, kan niet volgens de C++ standaard. Dat het misschien wel zou kunnen met een "theoretische" compiler/parser is leuk, maar afaik is geen compiler die dit daadwerkelijk toestaat :)

Het template trucje wat ik eerder aangaf, staat toe om je type pas later te definieren, maar dan zit je met lelijkere code, en mogelijk een langere compile-tijd, maar geen runtime-overhead.

Het pointer (danwel reference, hoewel ik dat nog lelijker vind dan pointer) trucje staat toe om een incompleet type te gebruiken, maar dat heeft wat runtime-overhead ivm dynamisch geheugen en indirection.

De enige oplossing zonder de source-code aan te passen is om zelf een parser/compiler te schrijven die het wel toestaat :P Ik verwacht niet dat de C++ standaard binnenkort veranderd gaat worden om dit toe te staan (tbh, ik denk dat er een heel goede reden is dat het niet mag, ook al weet ik die niet :P)

Verder heb ik ook geen azen-in-de-mouw, mocht je er iets op vinden, laat het weten :)

[ Voor 43% gewijzigd door MLM op 16-02-2011 20:08 ]

-niks-


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
MLM schreef op woensdag 16 februari 2011 @ 19:56:
[...]


Ehm, nee. Met een reference compiled het ook, maar als je je reference initialiseerd, zal je toch naar dynamisch geheugen moeten, want je gaat die reference moeten initialiseren met een object :)
C++:
1
2
3
4
5
6
7
class A;
class B
{
  A &a; //compiled wel, reference is ook gewoon een "pointer" onder de syntactische suiker, dus compleet type
  B() : a(A()) {} //instantie gaat direct uit scope -> undefined behavior
  B() : a(*new A()) {} //A in dynamisch geheugen, moet je een reference gaan opruimen (onintuitief), en is het gewoon een "hidden" pointer
};
Wat ik meer bedoelde is het volgende:
C++:
1
2
3
4
5
6
class A;
class B
{
  A &a;
  B(const A& a) : a(a) {} //Geen dynamisch geheugen en wel geinitialiseerd
};


Vaak wordt een klasse die als pointer of reference in de klass wordt opgeslagen aan de constructor meegegeven, en dat is meer wat ik bedoelde. In onze code base is deze constructie redelijk gebruikelijk.

Ik vermoed dat een van de reden is dat het geen Look-Ahead Left-to-Right parsable taal is.

[ Voor 47% gewijzigd door NC83 op 16-02-2011 21:40 ]

ex-FE Programmer: CMR:DiRT2,DiRT 3, DiRT Showdown, GRID 2, Mad Max


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

NC83 schreef op woensdag 16 februari 2011 @ 21:30:
[...]

Wat ik meer bedoelde is het volgende:
C++:
1
2
3
4
5
6
class A;
class B
{
  A &a;
  B(const A& a) : a(a) {} //Geen dynamisch geheugen en wel geinitialiseerd
};


Vaak wordt een klasse die als pointer of reference in de klass wordt opgeslagen aan de constructor meegegeven, en dat is meer wat ik bedoelde. In onze code base is deze constructie redelijk gebruikelijk.

Ik vermoed dat een van de reden is dat het geen Look-Ahead Left-to-Right parsable taal is.
Ja okay, maar dan is je A gewoon een object buitenom B, waar B toevallig gebruik van maakt :) Van de code van de TS kreeg ik meer het idee van "een A als onderdeel van B". Ik gebruik zelden references als members (wel veel als functie argument en functie variabelen)

-niks-


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dit is een regel die ik ook nooit helemaal begrepen heb. De regel is natuurlijk vrij duidelijk, maar ik denk niet (en dan heb ik er even goed over nagedacht hoe ik dat zou implementeren) dat het heel lastig is om wat jij wilt gewoon toe te staan. Met templates is het bovendien ook geen probleem (en zou wellicht een workaround voor je kunnen zijn)

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
43
44
45
46
// utilities
enum SingletonEnum { Instance };

template<class T, SingletonEnum>
struct MakeDependent
{
    typedef T type;
};


// je klassedefinities
struct A;

template<SingletonEnum S = Instance>
struct B_T
{
    typedef typename MakeDependent<A, S>::type A;
    A a;

    B_T();
    void Foo();
};
typedef B_T<> B;

int s = sizeof(B); // bliep, error


struct A
{
    int i;
};

int s = sizeof(B); // prima

// implementatie van B is wel wat meer typwerk
template<> // template<> nodig bij elke method en static field
void B::Foo() { } 

template<>
B::B_T() { } // ctors en dtor krijgen de naam van de template class, niet van de typedef

int main()
{
    B b;
    b.a.i = 4;
}


Wel denk ik dat als elke incomplete type per definitie een "dependent name" is (ook voor non-templates), het daadwerkelijk gebruik van een hele class lib er niet gemakkelijker op wordt. Nu is het gebruikelijk dat als je B wilt gebruiken louter B.h moet includen, en dan zit je goed. Na deze change zal A.h niet meer geinclude hoeven worden in B.h (en daar wilde je uiteindelijk naartoe), maar dat legt de verantwoordelijkheid bij de gebruiker van B - die moet A.h dan sowieso ook includen. Eigenlijk ben je er dus compleet niets mee geholpen.

Overigens kun je met bovenstaande truc ook circular dependencies oplossen (A die een B::Nested nodig heeft terwijl B een A::Nested nodig heeft)

[ Voor 35% gewijzigd door .oisyn op 16-02-2011 22:41 ]

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.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
.oisyn schreef op woensdag 16 februari 2011 @ 22:29:
Wel denk ik dat als elke incomplete type per definitie een "dependent name" is (ook voor non-templates), het daadwerkelijk gebruik van een hele class lib er niet gemakkelijker op wordt. Nu is het gebruikelijk dat als je B wilt gebruiken louter B.h moet includen, en dan zit je goed. Na deze change zal A.h niet meer geinclude hoeven worden in B.h (en daar wilde je uiteindelijk naartoe), maar dat legt de verantwoordelijkheid bij de gebruiker van B - die moet A.h dan sowieso ook includen. Eigenlijk ben je er dus compleet niets mee geholpen.
Dat is niet waar. Bovendien geldt dat al voor functies met parameters die forward declared zijn. Waarschijnlijk is jouw implementatie niet lazy genoeg. ;)
De layout van B heb je alleen nodig voor data members en sizeof. Als alle data members private zijn, blijft sizeof over. Als je B niet op de stack zet in een compile unit, heb je in die unit A helemaal niet nodig.

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op donderdag 17 februari 2011 @ 12:37:
[...]

Dat is niet waar. Bovendien geldt dat al voor functies met parameters die forward declared zijn. Waarschijnlijk is jouw implementatie niet lazy genoeg. ;)
De layout van B heb je alleen nodig voor data members en sizeof. Als alle data members private zijn, blijft sizeof over. Als je B niet op de stack zet in een compile unit, heb je in die unit A helemaal niet nodig.
Je hebt natuurlijk de size wel nodig, ook als je van de heap alloct (dus voor instantiatie van je object), het eerste impliciete argument van global operator new is namelijk sizeof(T) als je schrijft "new T()".

Maar als jij nooit members gebruikt van een class, en nooit op de stack zet of op de heap zet, waarom include je de file dan, immers gebruik je het hele object nooit :P

Je kan eventueel ook nog abstractie toepassen dmv virtuals:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//in A.h
class A
{
  virtual int some_method() = 0;
  virtual ~A() {}
  static A *create();
};

//in A.cpp
class A_impl
{
  virtual int some_method() { return 42; }
};

A *A::create() { return new A_impl(); }

Je kan dan A_impl zoveel veranderen als je wilt, alle ander files die A.h gebruiken zien geen changes, dus hoeven niet herbouwd. Een functie toevoegen of veranderen op A is natuurlijk wel een header-change. Maar goed, dan heb je ook weer een setje meer overhead (vtable, indirecte calls), en je probleem is nog steeds niet weg.

De beste oplossing die ik heb toegepast om dit probleem op te lossen in een redelijk grote solution met 100+ projecten met 1000+ .cpps die allemaal dezelfde header includen (gemiddelde bouwtijd bij verandering, 40min):
1) hercompile alleen de projecten waar je daadwerkelijk mee bezig bent (niet de hele solution)
2) ga koffie halen/naar de WC terwijl je bouwt, een SSD kan helpen :P
3) commit je changes van die headerfile pas naar source control pas nadat iedereen naar huis is, dan word je niet zo hard uitgescholden. commit bij voorkeur vanaf iemand anders workstation of account :)

-niks-


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

MLM schreef op donderdag 17 februari 2011 @ 14:08:
Maar als jij nooit members gebruikt van een class, en nooit op de stack zet of op de heap zet, waarom include je de file dan, immers gebruik je het hele object nooit :P
Hij heeft op zich wel een punt:
C++:
1
2
3
4
void foo(B * b)
{
    b->DoeIets();
}

Daar is de size van b niet voor nodig. Geldt ook voor nested types, die hebben helemáál niets te maken met de definitie van hun parent.

Full rebuilds zijn bij ons niet echt een issue meer sinds we Incredibuild gebruiken. De sourcefiles van verschillende subsystems allemaal onderbrengen in 1 translation unit (dmv includes) helpt ook best veel, ook kwa link tijden.

.edit: net even gecheckt, een full rebuild van Tomb Raider deed er 2:30 over.

[ Voor 5% gewijzigd door .oisyn op 17-02-2011 14:32 ]

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.


  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

.oisyn schreef op donderdag 17 februari 2011 @ 14:28:
[...]

Hij heeft op zich wel een punt:
C++:
1
2
3
4
void foo(B * b)
{
    b->DoeIets();
}

Daar is de size van b niet voor nodig. Geldt ook voor nested types, die hebben helemáál niets te maken met de definitie van hun parent.
<snip>
Maar wel de definitie van B, anders weet je niet wat "DoeIets" gaat zijn (ie, is het een functie, welke argumenten, return type etc), dus daar kan je sowieso niet wegkomen met een declaratie.

Voor nested types heb je wel een punt.

Incredibuild is natuurlijk wel fijn, maar dat is niet gratis. Meer sourcefiles in 1 translation unit duwen verhoogt volgens mij de kans alleen maar dat je je translation unit moet herbouwen (immers, meer dependencies op headers). In mijn ervaring (90% MSVC) heeft heeft linktijd weinig van doen met de hoeveelheid translation units tenzij je erg veel inline functies of template instantiatiosn met dezelfde types hebt rondlopen (dat worden dan duplicate COMDATs in elke .obj ongeveer). Een full rebuild van 2:30 kon ik enkel van dromen (maar tbh, het was behoorlijk veel linktijd in een "core" project (je weet wel, 1 met 1001 "handige" functies), static library met LTCG aan :P)

Maar ik heb relatief weinig headerfiles in mijn projecten die veel andere header files includen uit hetzelfde project, dus zo vaak heb ik geen "complete rebuild". OS/standard headers gaan gewoon in de PCH dus die zijn niet zo duur.

[ Voor 45% gewijzigd door MLM op 17-02-2011 15:03 ]

-niks-


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:27:
Ook kan het intressant zijn om een PCH te regelen voor stabiele headers (die dus niet veranderen, en niet afhankelijk zijn van header files die veranderen), dat kan compile-tijd flink verkorten. Moet je even de documentatie van je compiler/IDE doorzoeken hoe dat zit voor jou.
Dat was ik al van plan. Er wordt g++ (4.2) gebruikt. Is er een reden om systeemheaders niet in een PCH te zetten? Of is het toevoegen van een header via PCH zonder nadelen (behalve full rebuild als er iets veranderd)?

[ Voor 73% gewijzigd door Olaf van der Spek op 17-02-2011 15:47 ]


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op donderdag 17 februari 2011 @ 14:08:
Je hebt natuurlijk de size wel nodig, ook als je van de heap alloct (dus voor instantiatie van je object), het eerste impliciete argument van global operator new is namelijk sizeof(T) als je schrijft "new T()".
Dat is geen punt. Daar kan een (automagisch gegenereerde) get_size() voor gebruikt worden. Of een factory functie.
Maar als jij nooit members gebruikt van een class, en nooit op de stack zet of op de heap zet, waarom include je de file dan, immers gebruik je het hele object nooit :P
"private data members" != "members".
Functies zijn bijvoorbeeld gewoon te gebruiken.
De beste oplossing die ik heb toegepast om dit probleem op te lossen in een redelijk grote solution met 100+ projecten met 1000+ .cpps die allemaal dezelfde header includen (gemiddelde bouwtijd bij verandering, 40min):
Dat is een work around. ;)
2) ga koffie halen/naar de WC terwijl je bouwt, een SSD kan helpen :P
Waarom? Alle IO kan toch gecached worden?

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op donderdag 17 februari 2011 @ 15:42:
[...]

Dat was ik al van plan. Er wordt g++ (4.2) gebruikt. Is er een reden om systeemheaders niet in een PCH te zetten? Of is het toevoegen van een header via PCH zonder nadelen (behalve full rebuild als er iets veranderd)?
Systeemheaders wil je ALTIJD in de PCH zetten, daar is het voornamelijk voor bedoeld :)
Het idee is dat de compiler de PCH parsed, en dan de "state" opslaat in een file.
Alle files die daarna die PCH includen, kan dan de "state"-file openen, de "state" terughalen, en vanaf daar verder compilen (dan hoef je dus niet alle headers nog een keer te interpreteren). Je "betaalt" dus 1x veel tijd om de PCH te bouwen, en alle andere files zijn iets "goedkoper" daarna. Het idee is, dat de PCH dus niet vaak herbouwt hoeft te worden, dus die "state" kan hergebruikt worden als er daarna nog een keer gecompiled word.

Project-headers die zelden veranderen kan je ook prima in de PCH zetten. Het is juist niet de bedoeling om frequent gewijzigde headers in de PCH te zetten, tenzij je echt veel translation units hebt dat je de kosten eruit haalt elke build, maar dan zit je denk ik wel aan 50+ translation units te denken.

Nadeel aan PCH is natuurlijk dat elke translation unit die het gebruikt wel moet beginnen met #include "<pch>.h"

Ik weet niet of GCC/make/jouw IDE het vanzelf doet, maar het kan ook helpen om files parallel te compilen (bijv 4 translation units tegelijk compilen als je 4 cores in je PC hebt). Ik weet van MSVC dat die het wel automatisch doet, en dat kan wel wat tijd besparen. PCH build en linken profiteren hier niet van helaas (op project basis in elk geval, als je meerdere outputs hebt kan je die natuurlijk ook parallel linken).

Ik geloof dat I/O caching pas echt fijn werkt op Win7 (en mss vista), op XP nog niet zo heel erg. Op andere platformen zou ik niet weten :)

En dat "functie gebruiken" wat .oisyn claimde moet je wel je class voor definieren voor je het gebruikt (compleet type etc), want daar staan je functienamen en public members. Hoe dan ook moet je dus op een gegeven moment die header meepakken om te weten wat er mee kan, dus ik zie niet hoe dat je include-probleem zou oplossen

[ Voor 4% gewijzigd door MLM op 17-02-2011 16:10 ]

-niks-


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

MLM schreef op donderdag 17 februari 2011 @ 14:49:
[...]


Maar wel de definitie van B, anders weet je niet wat "DoeIets" gaat zijn (ie, is het een functie, welke argumenten, return type etc), dus daar kan je sowieso niet wegkomen met een declaratie.
Daar gaat het niet om. Het gaat om het hebben van de definitie van B, zonder dat je de definitie van A hoeft te hebben. Dat kan momenteel niet, maar voor de aanroep van een method van B is dat in feite prima mogelijk - daarvoor hoef je echt niet te weten wat de memory layout van B is.
Incredibuild is natuurlijk wel fijn, maar dat is niet gratis.
Het beats alle zelf gefabriceerde oplossingen, en zorgt voor een enorme tijdswinst voor je bedrijf. Effectief levert het dus geld op.
Meer sourcefiles in 1 translation unit duwen verhoogt volgens mij de kans alleen maar dat je je translation unit moet herbouwen (immers, meer dependencies op headers).
Tja, je kunt wel "volgens mij" erbij zeggen, maar het wordt enorm veel gedaan in de praktijk. En de verschillen bij grote projecten zijn zo klaar als een klontje :). Ja, uiteindelijk is de granulariteit veel groter waardoor je relatief meer moet compilen met een change. Daar staat tegenover dat headers veel minder vaak geparsed hoeven worden, waar gewoonweg de meeste tijd in gaat zitten.
In mijn ervaring (90% MSVC) heeft heeft linktijd weinig van doen met de hoeveelheid translation units tenzij je erg veel inline functies of template instantiatiosn met dezelfde types hebt rondlopen (dat worden dan duplicate COMDATs in elke .obj ongeveer).
Linktime heeft er juist ontzettend veel baat bij omdat de meeste inter-object dependencies in hetzelfde subsystem al tijdens het compileren geresolved kunnen worden. De linker heeft dus uiteindelijk veel minder uiteindjes die het aan elkaar hoeft te koppelen. Een typisch geval van divide & conquer.

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.


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op donderdag 17 februari 2011 @ 16:08:
Het idee is dat de compiler de PCH parsed, en dan de "state" opslaat in een file.
Ik weet hoe PCHs werken. ;)
Ik wil eigenlijk alleen weten of (en zo ja, hoeveel) een PCH met (veel) onnodige includes de compile tijd (van een file die de PCH gebruikt, niet van de PCH zelf) significant verhoogd.
Nadeel aan PCH is natuurlijk dat elke translation unit die het gebruikt wel moet beginnen met #include "<pch>.h"
Ja, dat moet MS nog oplossen. In g++ kun je gewoon -include pch.h gebruiken.

https://connect.microsoft...-without-include-stdafx-h
Ik weet niet of GCC/make/jouw IDE het vanzelf doet, maar het kan ook helpen om files parallel te compilen (bijv 4 translation units tegelijk compilen als je 4 cores in je PC hebt). Ik weet van MSVC dat die het wel automatisch doet, en dat kan wel wat tijd besparen. PCH build en linken profiteren hier niet van helaas (op project basis in elk geval, als je meerdere outputs hebt kan je die natuurlijk ook parallel linken).
make -j 4
En dat "functie gebruiken" wat .oisyn claimde moet je wel je class voor definieren voor je het gebruikt (compleet type etc), want daar staan je functienamen en public members. Hoe dan ook moet je dus op een gegeven moment die header meepakken om te weten wat er mee kan, dus ik zie niet hoe dat je include-probleem zou oplossen
Het include probleem gaat over onnodige dependencies en die worden veroorzaakt door data members. Is voor data members een declaratie voldoende dan is het probleem dus opgelost.

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Ah okay, ik begrijp hem nu:
C++:
1
2
3
4
5
6
7
8
9
10
11
class A; //incompleet type
class B
{
  A a;
  void foo();
};
int main()
{
  B *b = //factory method oid
  b->foo();
}

Dat zou inderdaad mogelijk moeten zijn om te parsen/compilen volgens mij (zelfs als foo virtual zou zijn, immers is je vtable meestal de eerste "member" in de layout). Misschien dat je het kan voorstellen als een extension voor GCC :)

@.oisyn: Ik dacht juist dat in LTCG dat juist niet gebeurde (release builds), omdat inter-translation-unit inlining etc nog mogelijk is. De linker kan pas als ie alle functies heeft inzien welke dingen hij het best kan inlinen. (een one-liner in een andere translation unit zou anders altijd een call moeten worden). Maar goed, ik geloof je op je woord in dit geval, mijn ervaring met grote projecten is niet erg groot (en diegene waar ik mee gewerkt heb waren volgens mij gewoon een ramp qua opzet).

@Olaf:
Ja, dat moet MS nog oplossen. In g++ kun je gewoon -include pch.h gebruiken.
Je hebt volgens mij een /FI (force include) mogelijkheid op de commandline. Of dat werkt met PCH hebik nooit geprobeerd (maar ik zie niet in waarom niet)

[ Voor 12% gewijzigd door MLM op 17-02-2011 16:35 ]

-niks-


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op donderdag 17 februari 2011 @ 16:34:
Je hebt volgens mij een /FI (force include) mogelijkheid op de commandline. Of dat werkt met PCH hebik nooit geprobeerd (maar ik zie niet in waarom niet)
Het werkt, nice!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

MLM schreef op donderdag 17 februari 2011 @ 16:08:
Ik weet niet of GCC/make/jouw IDE het vanzelf doet, maar het kan ook helpen om files parallel te compilen (bijv 4 translation units tegelijk compilen als je 4 cores in je PC hebt).
Bij GCC wordt meestal aangeraden om aantal cores+1 hiervoor te nemen. Veel van de tijd zit hem ook in het wachten op de disks, met meer threads dan codes heb je dus altijd wat overlap. Met Automake/GCC kan je trouwens ook vrij eenvoudig je hele project vanaf je ram compileren, waardoor je dus geen disk access meer hebt. Dit vreet echter wel enorm veel ram...

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Het lijkt me ook een beetje nutteloos, als je vaak compilet dan zitten de sourcefiles toch wel in de diskcache van het OS. Het enige voordeel is dat het niet gepruned wordt.

[ Voor 17% gewijzigd door .oisyn op 17-02-2011 20:50 ]

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.


  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Het schijnt toch wel tot 30% in tijd te kunnen schelen heb ik her en der gelezen. En vooral het linken is een stuk sneller.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Daar kunnen we niet zoveel mee.

Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

:+
The average package will not be sped up by much. But emerging in tmpfs hurts only if you run out of memory. And certain emerges / operations like checking out from git can be sped up considerably. If you have encrypted root, then using tmpfs is also more convenient than creating an extra partition for an unencrypted filesystem.
In de gevallen dat je primaire disk dus traag is heeft het zeker veel effect. In het verleden heb ik het gebruikt bij een encrypted root disk en dat was een verademing.

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Ach ja, linux heeft vast niet zo'n fatsoenlijke disk cache zoals Windows ;)

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.


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:35
.oisyn schreef op vrijdag 18 februari 2011 @ 02:01:
Ach ja, linux heeft vast niet zo'n fatsoenlijke disk cache zoals Windows ;)
Help!

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.


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
De belangrijkste winst die nog te realiseren valt zijn combineerbare precompiled headers. Nu kun je maximaal 1 "precompiled header" hebben, die dan wel meerdere andere headers mag includen. Het zou echter een stuk handiger zijn als je gewoon <vector.pch>, <string.pch>, <windows.h.pch> naast elkaar kunt hebben.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dat lijkt me knap lastig te realiseren, een macro gedefinieerd in de ene header kan de contents van de andere header beïnvloeden. Je kunt dus niet echt meer "precompilen", je kunt hoogstens tokenizen.

C++:
1
2
3
4
5
6
7
8
9
10
// A.h
#ifndef SOMETYPE
#define SOMETYPE int
#endif

void Foo(SOMETYPE v);


// B.h
#define SOMETYPE float

Als je B.pch voor A.pch include, dan krijg je een Foo(float). Als je enkel A.pch include, dan krijg je een Foo(int).

[ Voor 38% gewijzigd door .oisyn op 18-02-2011 12:59 ]

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.


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Volgens mij kan dat niet zomaar. Voorbeeld:
C++:
1
2
3
4
5
6
7
8
9
10
11
//<common>
#ifndef TYPE_DEFINED
#define TYPE_DEFINED
typedef struct { int foo; } TYPE;
#endif

//<string> bevat
#include <common>

//<vector> bevat
#include <common>


Dan kan je nooit meer die 2 PCH's combineren, want dan heb je dubbel TYPE defined. Dit is niet echt farfetched, stdint of yvals doen dit, en worden ge-include door 1001 andere headers.

Edit: .oisyn had hetzelfde bedacht :(

[ Voor 5% gewijzigd door MLM op 18-02-2011 13:10 ]

-niks-


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Anyway, wat mij betreft gaat het hele translation unit en include systeem op de schop, en wordt er gewerkt met modules oid zoals in andere talen gebruikelijk is.

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.


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

uhu. C++0x is nog steeds niet standaard, ze zijn al 8(?) jaar bezig met een paar relatief minder ingrijpende veranderingen dan dat, ik gok dat je sneller een nieuwe taal kan ontwikkelen dan C++ veranderen. het standards committee is zo rigide dat ik niet denk dat dit er OOIT door gaat komen :P

-niks-


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

http://www.open-std.org/j...ocs/papers/2007/n2316.pdf
Niet afgeschoten, maar komt niet in C++0x. De status is "heading for a seperate TR"

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.


Acties:
  • 0 Henk 'm!

  • LauPro
  • Registratie: Augustus 2001
  • Laatst online: 19-09 16:51

LauPro

Prof Mierenneuke®

Het risico is natuurlijk dat dit soort optimalisaties in C++0x op termijn nog nauwelijks zin hebben omdat de processoren over 10-15 jaar dusdanig snel zijn dat het geen hond meer uit maakt :+ .

Inkoopacties - HENK terug! - Megabit
It is a war here, so be a general!


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

Dan kan er ook weer meer CPU tijd worden gestoken in optimizing compilers.

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.


Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
De truc om meerdere PCHs te kunnen gebruiken is inderdaad iets gecompliceerd door macro's. Dar probleem los je op 2 manieren op

1, je mag niet zomaar alles definen voor een standaard header. #define float is illegaal.
2, headers bevatten vaak #ifdefs; die maken al duidelijk welke macro's verwacht worden.
Vaak kun je deze zelfs efficient parsen, bijvoorbeeld omdat ze een hele class omvatten.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MSalters schreef op vrijdag 18 februari 2011 @ 12:46:
De belangrijkste winst die nog te realiseren valt zijn combineerbare precompiled headers. Nu kun je maximaal 1 "precompiled header" hebben, die dan wel meerdere andere headers mag includen. Het zou echter een stuk handiger zijn als je gewoon <vector.pch>, <string.pch>, <windows.h.pch> naast elkaar kunt hebben.
Wat is het voordeel ten opzichte van één PCH met al die headers?
.oisyn schreef op vrijdag 18 februari 2011 @ 14:03:
Anyway, wat mij betreft gaat het hele translation unit en include systeem op de schop, en wordt er gewerkt met modules oid zoals in andere talen gebruikelijk is.
Wat is een module precies? En wat zou het voordeel zijn ten opzichte van het toestaan van een class met incomplete data members?

[ Voor 29% gewijzigd door Olaf van der Spek op 18-02-2011 19:53 ]


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:42

.oisyn

Moderator Devschuur®

Demotivational Speaker

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.


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Interessant. Maar of modules vereisen incomplete class data members of ze lossen dat probleem niet op.
MLM schreef op vrijdag 18 februari 2011 @ 14:08:
uhu. C++0x is nog steeds niet standaard, ze zijn al 8(?) jaar bezig met een paar relatief minder ingrijpende veranderingen dan dat, ik gok dat je sneller een nieuwe taal kan ontwikkelen dan C++ veranderen. het standards committee is zo rigide dat ik niet denk dat dit er OOIT door gaat komen :P
Waar zijn ze dan zolang mee bezig geweest? Concepts en memory model waren meer ingrijpende wijzigingen (IMO).

[ Voor 46% gewijzigd door Olaf van der Spek op 19-02-2011 11:54 ]


Acties:
  • 0 Henk 'm!

  • MLM
  • Registratie: Juli 2004
  • Laatst online: 12-03-2023

MLM

aka Zolo

Olaf van der Spek schreef op zaterdag 19 februari 2011 @ 11:53:
[...]

Waar zijn ze dan zolang mee bezig geweest? Concepts en memory model waren meer ingrijpende wijzigingen (IMO).
En concepts hebben ze er dan ook gewoon uitgekicked (dat word dus voor C++210x oid), omdat "de taal er niet klaar voor was". Ik begrijp echt wel het nut van standaardisatie, maar doordat er zo langzaam gereageerd word, gaan compilerbouwers extensions introduceren om features maar mogelijk te maken, en dat werkt dus gewoon de verkeerde kant op (immers, elke compiler implementeerd een feature net anders, en met andere keywords etc). Als je kijkt naar de progressie die geboekt word in talen die niet zo traag in aanpassing zijn (bijvoorbeeld C#) in slecht een paar jaar, doet mij vrezen voor de bruikbaarheid van C++ in de nabije toekomst.

-niks-


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op zaterdag 19 februari 2011 @ 13:25:
En concepts hebben ze er dan ook gewoon uitgekicked (dat word dus voor C++210x oid), omdat "de taal er niet klaar voor was".
Concepts was (volgens mij) te complex en nog niet goed uitgewerkt.
Ik begrijp echt wel het nut van standaardisatie, maar doordat er zo langzaam gereageerd word, gaan compilerbouwers extensions introduceren om features maar mogelijk te maken, en dat werkt dus gewoon de verkeerde kant op (immers, elke compiler implementeerd een feature net anders, en met andere keywords etc). Als je kijkt naar de progressie die geboekt word in talen die niet zo traag in aanpassing zijn (bijvoorbeeld C#) in slecht een paar jaar, doet mij vrezen voor de bruikbaarheid van C++ in de nabije toekomst.
C# is proprietary en heeft een groot bedrijf achter zich, dan gaat het allemaal wat sneller.
Maar je hebt wel gelijk, waarom sommige dingen zo langzaam gaan weet ik ook niet.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:35
MLM schreef op zaterdag 19 februari 2011 @ 13:25:
Als je kijkt naar de progressie die geboekt word in talen die niet zo traag in aanpassing zijn (bijvoorbeeld C#) in slecht een paar jaar, doet mij vrezen voor de bruikbaarheid van C++ in de nabije toekomst.
C# lijkt me eigenlijk geen 'concurrent' van C++. Misschien op het Windows platform.

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.


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
MLM schreef op woensdag 16 februari 2011 @ 13:27:
Ook kan het intressant zijn om een PCH te regelen voor stabiele headers (die dus niet veranderen, en niet afhankelijk zijn van header files die veranderen), dat kan compile-tijd flink verkorten. Moet je even de documentatie van je compiler/IDE doorzoeken hoe dat zit voor jou.
In VC is het simpel, maar van automake heb ik geen kaas gegeten. Heeft iemand ervaring met automake / gcc en PCH?

Acties:
  • 0 Henk 'm!

  • Caelorum
  • Registratie: April 2005
  • Laatst online: 20:07
Olaf van der Spek schreef op zaterdag 19 februari 2011 @ 19:03:
[...]

Concepts was (volgens mij) te complex en nog niet goed uitgewerkt.

[...]

C# is proprietary en heeft een groot bedrijf achter zich, dan gaat het allemaal wat sneller.
Maar je hebt wel gelijk, waarom sommige dingen zo langzaam gaan weet ik ook niet.
De nieuwere versies misschien maar het is wel degelijk voor een deel open (voglens mij heel C#2.0)

Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Caelorum schreef op maandag 28 februari 2011 @ 19:07:
[...]

De nieuwere versies misschien maar het is wel degelijk voor een deel open (voglens mij heel C#2.0)
Dat is nauwelijks relevant. Als MS de grootste C# apps durft te demonstreren op een free/open implementatie (Mono?), dan is het relevant.

Acties:
  • 0 Henk 'm!

  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 13-09 00:05
C# is volledig standaard AFAICT, en hetzelfde geldt voor de CLI. Wat niet standaard is, zijn zaken zoals WinForms en andere libraries.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:35
MSalters schreef op dinsdag 01 maart 2011 @ 11:38:
C# is volledig standaard AFAICT, en hetzelfde geldt voor de CLI. Wat niet standaard is, zijn zaken zoals WinForms en andere libraries.
Een standaard compiler/CLI met een non-standaard library erbij. De kans op een Windows only applicatie wordt dan wel erg groot.

Daarnaast heb je nog de COM interop fratsen en Win32 API declares die in een behoorlijk aantal applicaties voorkomen.

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.

Pagina: 1