[C++] Initialisatie van static const object

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
Ik heb de gewoonte van java en C# om standaardwaarden en dergelijke als member variabelen te zetten
(dus dat je bvb connector.connect (int port) kan aanspreken met connector.connect(connector.defaultport) zeg maar).

Ik heb de indruk dat dat ook de techniek is die in C++ gangbaar is (preprocessor constanten werken wel nog maar ze raden overal const aan). Ik zou graag bevestiging hebben dat dat inderdaad zo is, voor ik een verkeerde techniek aanleer.

Op dit moment heb ik echter ook een concreet probleem. Ik heb een nieuwe klasse gemaakt "dimensie"

C++: Dimensie.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Dimensie
{
public:
        Dimensie(void);
        ~Dimensie(void);


        //Getters & setters
    unsigned Rijen(){return rijen;}
        void Rijen(int aantalRijen) {this->rijen=aantalRijen;}
    unsigned Kolommen(){return kolommen;}
        void Kolommen(int aantalKolommen) {this->kolommen=aantalKolommen;}

private:
    unsigned rijen, kolommen;
};


en ben nu bezig met een andere klasse te maken :
C++: toolkit.h
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
class Toolkit
{
public://Constructors
        Toolkit(void);
public://Destructor
        ~Toolkit(void);
public://Methods
        <snip>

        /**
         *Display a two dimensional uint8_t array with a 4*4 dimension as a 2D matrix, with a string as display name.
         */
        static void DisplayMatrix(uint8_t **block, string name);

        /**
         *Display a two dimensional uint8_t array with a given dimension as a 2D matrix, with a string as display name.
         */
        static void DisplayMatrix(uint8_t **block, int horizontal_dimension, int vertical_dimension, string name);

        <snip>

        static const Dimensie standaardDimensie;<probleembron>
        
};
const Dimensie Toolkit::standaardDimensie.<probleem1> = <probleem2>;


Zoals je kan zien wil ik een static const variabele aanmaken van het type van mijn klasse, een dimensie.
Het probleem is nu echter dat ik bij <probleembron> heb gevonden in de cursussen van C++ die ik heb dat je die dus braaf zo moet declareren, maar niet definieren, en dat je die buiten de body zou moeten definiëren.

Daar was ik dus mee bezig, maar blijkbaar kan die bij <probleem1> niet aan de members om één of andere reden? Mijn idee was om alle members handmatig via de setters te initialiseren, vermits ik geen constructor heb (als ik het goed begrepen heb kan je die daar toch niet eens aanspreken) want dan komen we bij <probleem2> .

Dat probleem 2 was namelijk dat het enige voorbeeld dat ik gevonden heb met klassen de string klasse gebruikte, en die is natuurlijk netjes met operator = en al gedefinieerd waardoor die een initialisatie in de stijl van een int (const var naam = waarde) aankan.

Het probleem is dus : Hoe initialiseer ik een (static) const object op correcte wijze?

Acties:
  • 0 Henk 'm!

  • TheWickedD
  • Registratie: Juli 2002
  • Laatst online: 02-04-2024
Hoi! Ik weet niet zeker hoe het met een static zit (waarom is hij static), maar een const member kun je alleen initializeren dmv een initialization list

Acties:
  • 0 Henk 'm!

  • VyperX
  • Registratie: Juni 2001
  • Laatst online: 14-08 13:04
Zoals TheWickedD al zegt: een const object kan je alleen aanmaken met behulp van zijn constructor. Niet van toepassing hier, maar bij een const member object zal je deze constructor in de member initialization list moeten aanroepen.

Het handigste hier zal dus zijn om zelf een nieuwe constructor te definieren voor je Dimensie class.

Btw, je zegt verder dat je in 'toolkit.h' het volgende doet:
C++:
1
const Dimensie Toolkit::standaardDimensie.<probleem1> = <probleem2>;

Je realiseert je dat deze static variabele dan in elke object file terecht komt waar je die 'toolkit.h' include? Oftewel: bij het linken ga je problemen krijgen doordat het object meerdere keren bestaat (in verschillende files).
Om deze reden worden static objects altijd in de .cpp file geinstantieerd.

My Dwarf Fortress ASCII Reward: ~~@~~####,.".D",.B""


Acties:
  • 0 Henk 'm!

  • jmzeeman
  • Registratie: April 2007
  • Laatst online: 12-09 16:17
Om je static const te initialiseren moet je een constructor met parameters toevoegen aan je Dimensie class, daarna kan je je const static member initializeren in je cpp file (dus in toolkit.cpp). Zet daar de constante zonder static neer gevolgd door de parameters. De constante wordt dan maar één keer opgeslagen (in de toolkit object file) en alle andere files refereren hier dan naar.

BIjvoorbeeld:

Dimensie.h:
C++:
1
2
3
4
5
6
7
class Dimensie 
{ 
public: 
        Dimensie(void); 
        Dimensie(int rijen, int kolommen);
        ~Dimensie(void); 
<...>

Dimensie.cpp
C++:
1
2
3
4
5
6
7
<...>
Dimensie::Dimensie(int rijen, int kolommen)
{
          this->rijen=rijen;
          this->kolommen=kolommen;
}
<...>


ToolKit.cpp:
C++:
1
2
3
<...>
const Dimensie Toolkit::standaardDimensie(2,2)
<...>


@TheWickedD
Om gewone const members te gebruiken moet je eerst een object van de class aanmaken voordat je hem gaat gebruiken. Ook worden deze per object opgeslagen en kunnen ze per object verschillen. const static members worden maar een keer per programma opgeslagen en kunnen zonder een object aan te maken worden aangesproken. Deze kunnen dus in tegenstelling tot niet const static members worden gebruikt in of bij het aanroepen van static methods en de constructor.
Voorbeeld van een class met mogelijk verschillende const members:
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
header:
#pragma once
class CTest
{
public:
    CTest(void);
    CTest(int myConst);
    const static int ClassConst; 
    const int InstanceConst; 
};

cpp:
#include "Test.h"

const int CTest::ClassConst = 1; 

CTest::CTest(void)
:InstanceConst(2)
{
}

CTest::CTest(int myConst)
:InstanceConst(myConst)
{
}


@.oisyn
Oeps, in mijn wil om even snel een simpel voorbeeldje te geven een foutje gemaakt. Als je overal char * met int of je favoriete string klasse (+de bijbehorende andere wijzigingen) vervangt klopt t wel. |:(
voorbeeltje is gefixed.

[ Voor 52% gewijzigd door jmzeeman op 17-08-2009 13:21 . Reden: @TheWickedD / taalfoutjes / char* naar int ]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Als je huidige constructor default waardes aan je object geeft hoef je geen specifieke constructor te maken, je kunt dan gewoon gebruik maken van de compiler gegenereerde copy constructor en assignment operator.

Een C++ compiler geeft je altijd drie functies die voor een class, Default constructor, copy constructor en assignment operator. Het is dan ook om deze reden dat als je ofwel de copy constructor of de assignment operator implementeert voor je class je de andere ook moet implementeren.

In jouw voorbeeld is de default gegenereerde copy constructor en assignment operator voldoende. Maakte je echter gebruik van references en pointers dan moet je gaan kijken naar een specifieke copy constructor en assignment operator (zie ook shallow copy).

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

jmzeeman schreef op maandag 17 augustus 2009 @ 10:20:
Voorbeeld van een class met mogelijk verschillende const members:
Die members zijn niet const hoor ;)
NC83 schreef op maandag 17 augustus 2009 @ 11:50:
Een C++ compiler geeft je altijd drie functies die voor een class, Default constructor, copy constructor en assignment operator.
Let wel, de default constructor is er alleen als je geen andere constructors hebt gedefinieerd. En zodra je een object in je class hebt zitten dat een specifieke non-default constructie vereist (zoals references of types zonder defaut ctor), dan moet je sowieso een ctor implementeren om die class te kunnen instantieren.

[ Voor 16% gewijzigd door .oisyn op 17-08-2009 13:06 ]

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op maandag 17 augustus 2009 @ 01:53:
C++: Dimensie.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Dimensie
{
public:
        Dimensie(void);
        ~Dimensie(void);


        //Getters & setters
    unsigned Rijen(){return rijen;}
        void Rijen(int aantalRijen) {this->rijen=aantalRijen;}
    unsigned Kolommen(){return kolommen;}
        void Kolommen(int aantalKolommen) {this->kolommen=aantalKolommen;}

private:
    unsigned rijen, kolommen;
};
Ik zou in deze code trouwens wel een type gebruiken als ik jou was, in dit geval wordt een unsigned integer aangenomen maar dat zou wel eens anders kunnen zijn in een andere compiler.
unsigned is een type modifier die aangeeft dat het type wat je gebruikt geen sign bevat, dus geen plus of min.
Daarnaast is het gebruik van "this->" niet noodzakelijk aangezien dat altijd wordt toegepast in een member function. Je hebt het natuurlijk wel nodig als een van je parameters dezelfde naam heeft als een member variable.

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

NC83 schreef op maandag 17 augustus 2009 @ 13:32:
[...]


Ik zou in deze code trouwens wel een type gebruiken als ik jou was, in dit geval wordt een unsigned integer aangenomen maar dat zou wel eens anders kunnen zijn in een andere compiler.
Onzin, "unsigned" is per definitie een alias voor "unsigned int". Het is dan ook geen type modifier. Dit mag om die reden ook niet:
C++:
1
2
typedef int myint;
unsigned myint bla;


Het is natuurlijk wel raar dat de setters een signed int verwachten terwijl het vervolgens in een unsigned int opgeslagen wordt.

[ Voor 27% gewijzigd door .oisyn op 17-08-2009 14:21 ]

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
Ah, bedankt, Initialisation lists zijn wat ik nodig had.
Maar nu je het zegt, zonder dat de constructor geroepen is, wie initialiseert dan m'n static variabele? Hij moet static zijn omdat ik hem nodig heb om de klasse zelf te initialiseren, dus hij moet al bestaan voor ik een klasse van dat type dat die variabele bevat maak.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op maandag 17 augustus 2009 @ 16:06:
Maar nu je het zegt, zonder dat de constructor geroepen is, wie initialiseert dan m'n static variabele?
Gebeurt automatisch aan het begin van je programma. Alleen moet je de definitie van de static nog wel even in toolkit.cpp zetten

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
VyperX schreef op maandag 17 augustus 2009 @ 07:26:
Zoals TheWickedD al zegt: een const object kan je alleen aanmaken met behulp van zijn constructor. Niet van toepassing hier, maar bij een const member object zal je deze constructor in de member initialization list moeten aanroepen.
Hoezo niet van toepassing? Het is toch een member object? En het is const? En de "member initilization list" is toch hetzelfde als "initilization list"?
Het handigste hier zal dus zijn om zelf een nieuwe constructor te definieren voor je Dimensie class.
Jep dat lijkt me ook
Btw, je zegt verder dat je in 'toolkit.h' het volgende doet:
C++:
1
const Dimensie Toolkit::standaardDimensie.<probleem1> = <probleem2>;

Je realiseert je dat deze static variabele dan in elke object file terecht komt waar je die 'toolkit.h' include? Oftewel: bij het linken ga je problemen krijgen doordat het object meerdere keren bestaat (in verschillende files).
Om deze reden worden static objects altijd in de .cpp file geinstantieerd.
Oei ja je hebt gelijk, dat was ik al weer vergeten dat dat verschil uitmaakte in welke file je iets doet. Korte termijn geheugen...

Maar....nu heb je het wel over static?Het lijkt me niet dat het uitmaakt of die static is, zolang die gedefinieerd wordt in de .h file zijn er problemen, of dat nu static is of niet?

Nu bedenk ik me ook dat, functies die kort worden gedefinieerd, van de aard van getters ens etters met alleeniets als
C++:
1
 void func(int y) {x=y} 
die je gewoon in de header laat staan, waarom worden die dan niet dubbel gedefinieerd als je de .h file meerdere keren include?

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 16:11:
[...]

Gebeurt automatisch aan het begin van je programma. Alleen moet je de definitie van de static nog wel even in toolkit.cpp zetten
Dus voor een object, iets als
C++: foo.h
1
2
3
class foo {
    foo(int x){}//mag die definitie hier (de  "{}" dus)? - zie vorige post
}
C++: bla.h
1
2
3
4
5
class bla
{
public:
      static const foo bar;
}
C++: bla.cpp
1
2
//hier geen static meer bij he?
const foo bla::bar(3);

Dat zou alles moeten zijn wat je nodig hebt om het aan de praat te krijgen dat je nu van éénderwaar in je code, waar je de file bla.h include, aan bla kunt?

Als die const is, moeten dan al z'n methods (getters) ook const zijn? Anders kan je niks er mee denk ik?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op maandag 17 augustus 2009 @ 16:14:
[...]
Hoezo niet van toepassing? Het is toch een member object? En het is const? En de "member initilization list" is toch hetzelfde als "initilization list"?
Het is een member, maar geen instance member. De storage is dus per class, ipv per object. Verder:
C++:
1
2
3
4
5
6
7
8
9
MyClass::MyClass()
// member initializer list
:    BaseClass(34),     
     member1(1),
     member2("hoi")
{
}

SomeStruct s = { 1, 2, 3 }; // initializer list

Dus nee, die zijn niet hetzelfde :). Die onderste variant werkt ook alleen maar voor aggregate types (classes en structs zonder zelf-gedefinieerde constructors)
Maar....nu heb je het wel over static?Het lijkt me niet dat het uitmaakt of die static is, zolang die gedefinieerd wordt in de .h file zijn er problemen, of dat nu static is of niet?
Als ze niet static zijn is de declaratie in de class zelf genoeg he :). Er is ook een instantie van die member per class instance, dus er is ook geen enkele reden om ze los in een translation unit (source file) te definieren. Pas als ze static zijn dan moet je, net als globale variabelen, ze ook definieren in een specifieke translation unit (anders heeft uiteindelijk geen enkele file de definitie van die variabele, en dan krijg je link errors)
Nu bedenk ik me ook dat, functies die kort worden gedefinieerd, van de aard van getters ens etters met alleeniets als
C++:
1
 void func(int y) {x=y} 
die je gewoon in de header laat staan, waarom worden die dan niet dubbel gedefinieerd als je de .h file meerdere keren include?
Je bedoelt member functions? Dat komt omdat ze impliciet inline zijn als je ze binnen een class definieert. Dit geldt overigens, itt static variabelen, ook voor static functies.


@ post hierboven: klopt helemaal :). Methoden die de observable state van het object niet veranderen kun je sowieso beter altijd const maken. Dus dat geldt typisch ook voor getters :)

[ Voor 4% gewijzigd door .oisyn op 17-08-2009 16:58 ]

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Daarnaast is het zo dat je static const int in een class in de header kunt initialiseren, alle andere types dan int moeten in de CPP worden geinitialiseerd.

Als voorbeeld:

.h file
C++:
1
2
3
4
5
6
7
8
9
10
11
class FooBar
{
public:
    FooBar() {}
    ~FooBar() {}
protected:
private:
    static const int m_staticInt = 3;
    static const float m_staticFloat;
    static const char* m_staticChar;
}


In .cpp
C++:
1
2
    const float FooBar::m_staticFloat = 0.5f;
    const char* FooBar::m_staticChar = "FooBar Static Const Char *";

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

NC83 schreef op maandag 17 augustus 2009 @ 16:39:
Daarnaast is het zo dat je static const int in een class in de header kunt initialiseren, alle andere types dan int moeten in de CPP worden geinitialiseerd.
Even mierenneuken: dit geldt voor álle integral en enum types, niet alleen voor int. Dus bijv. ook unsigned long en bool.

Daarnaast maak je nu dezelfde fout als TheWickedD deed: m_staticChar is niet const ;)

C++:
1
2
3
4
5
6
class FooBar
{
    // ...
    static const char* const m_staticChar;
    //                  ^-- nu wel
}

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
jmzeeman schreef op maandag 17 augustus 2009 @ 10:20:
Om je static const te initialiseren moet je een constructor met parameters toevoegen aan je Dimensie class, daarna kan je je const static member initializeren in je cpp file (dus in toolkit.cpp). Zet daar de constante zonder static neer gevolgd door de parameters. De constante wordt dan maar één keer opgeslagen (in de toolkit object file) en alle andere files refereren hier dan naar.
Aha :)

Dat lijkt op wat ik dacht ja...

Dimensie.h:extra constructor toegevoegd aan dimensie klasse waarmee jje in Dimensie.cpp members initialiseert.
ToolKit.cpp:en dan dus een const van dat type initialiseert met haakjes en vooral niet in de initialisation list in tegenstelling tot gewone const zo te zien.
@TheWickedD
>>> yep dat is precies wat ik bedoelde.
Voorbeeld van een class met mogelijk verschillende const members:
_/-\o_
@.oisyn
Oeps, in mijn wil om even snel een simpel voorbeeldje te geven een foutje gemaakt. Als je overal char * met int of je favoriete string klasse (+de bijbehorende andere wijzigingen) vervangt klopt t wel. |:(
voorbeeltje is gefixed.
Had je een const pointer gemaakt? Die zijn nog vrij chinees voor mij :)

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 16:25:

Dus nee, die zijn niet hetzelfde :). Die onderste variant werkt ook alleen maar voor aggregate types (classes en structs zonder zelf-gedefinieerde constructors)
AAAAAAAAAAAAAAAAAArrrghH! *BENG* (m'n kop ontploft)

<veeeel te veel mogelijkheden>
Dat er over zo'n simpel ding zoveel gezegd kan worden - wat een topic :D

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Das C++ a million ways to shoot yourself in the foot :P

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 11:50:
Als je huidige constructor default waardes aan je object geeft hoef je geen specifieke constructor te maken, je kunt dan gewoon gebruik maken van de compiler gegenereerde copy constructor en assignment operator.

Een C++ compiler geeft je altijd drie functies die voor een class, Default constructor, copy constructor en assignment operator.
Die compiler gegenereerde copy constructor en assignment operator, hoe nuttig zijn die?
Want ik meen dat als je geen assignment operator (de "=" toch?) declareert en definieert in je klasse, dat hij dan gewoon de pointers aan mekaar gelijksteld? Wacht nee... da's in java dat de = je referentie naar je object kopieert, hier kan je apart aan je objectpointer en je *objectpointer (object zelf) dus.... als je geen "=" definieert... wat voor eentje maakt hij dan? Zelfde vraag voor de copy constructor, hoe nuttig is die?

Ik meen te begrijpen dat die alle member waarden kopieert...volgens mij zijn ze dan perfect identiek... dus waarom zou je dan oooit die dingen zelf implementeren, als je toch al perfecte 1:1 kopiën krijgt?
Het is dan ook om deze reden dat als je ofwel de copy constructor of de assignment operator implementeert voor je class je de andere ook moet implementeren.

In jouw voorbeeld is de default gegenereerde copy constructor en assignment operator voldoende. Maakte je echter gebruik van references en pointers dan moet je gaan kijken naar een specifieke copy constructor en assignment operator (zie ook shallow copy).
Over welk voorbeeld gaat het eigenlijk? Dat van mijn topic start?

Dat je door de een constructor te implementeren de default constructor kwijt raakt snap ik, is ook nuttig. Maarrr... waarom verknoeid een assignment of copy constructor de respectievelijke andere default?

En met de references en pointers ben je me kwijt... ow wacht... hij kopieert die references/pointers gewoon, waardoor die naar hetzelfde geheugen wijzen... je zou dus eigenlijk de waarden waar ze naar wijzen opnieuw moeten maken en alles daar in kopiêren, om een identiek, maar onafhankelijk object te krijgen... juist?

Is dat wat een shallow copy is? Alleen de pointers, niet de inhoud? (een reference is voor zover ik weet ook gewoon een "pointer", behalve dat hij altijd const is en je hem niet moet de-referencen met * ).

[ Voor 1% gewijzigd door Rygir op 17-08-2009 17:57 . Reden: welk voorbeeld? ]


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op maandag 17 augustus 2009 @ 17:54:
En met de references en pointers ben je me kwijt... ow wacht... hij kopieert die references/pointers gewoon, waardoor die naar hetzelfde geheugen wijzen... je zou dus eigenlijk de waarden waar ze naar wijzen opnieuw moeten maken en alles daar in kopiêren, om een identiek, maar onafhankelijk object te krijgen... juist?

Is dat wat een shallow copy is? Alleen de pointers, niet de inhoud? (een reference is voor zover ik weet ook gewoon een "pointer", behalve dat hij altijd const is en je hem niet moet de-referencen met * ).
Precies als je er meer over wilt weten moet je de "gang of three rule" eens opzoeken

C++ copy constructor doet een shallow copy, dus als je pointers in je classe hebt krijgen die dezelfde waarde. De pointer zal dus naar het zelfde object als het origineel wijzen. Je krijgt hier problemen doordat als je het origineel vernietigd inclusief het object waar de pointer daarin verwijst. De pointer in de copy zal dan naar een stuk geheugen wijzen dat niet noodzakelijker wijze het object is dat je verwacht.

Een reference is een alias voor een variable en moet altijd een waarde hebben, dit betekent dat je een reference kan gebruiken ipv een variable.

[ Voor 51% gewijzigd door NC83 op 17-08-2009 18:08 ]

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 12:29:
Die members zijn niet const hoor ;)
Wat had hij gedaan, constante pointers gemaakt?
Let wel, de default constructor is er alleen als je geen andere constructors hebt gedefinieerd. En zodra je een object in je class hebt zitten dat een specifieke non-default constructie vereist (zoals references of types zonder defaut ctor), dan moet je sowieso een ctor implementeren om die class te kunnen instantieren.
Goed punt, verklaart mij ook weer iets ivm references. Als je een member hebt in de aard van
C++:
1
2
3
4
class foo 
{
 &int bar;
}

dan moet je... ergens (waar? in de .h of de .cpp?)
C++:
1
bar=&2;
of
C++:
1
foo:foo(int bar){this->bar=&bar;}
of zoiets hebben?

Ik kan me ook even niet indenken waarom je dat zo zou doen... je maakt een alias naar iets buiten je class, is dat niet heel erg gevaarlijk? En binnen je class, waarom zou je dat als member doen?

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op maandag 17 augustus 2009 @ 18:03:
[...]
Wat had hij gedaan, constante pointers gemaakt?

[...]
Goed punt, verklaart mij ook weer iets ivm references. Als je een member hebt in de aard van
C++:
1
2
3
4
class foo 
{
 &int bar;
}

dan moet je... ergens (waar? in de .h of de .cpp?)
C++:
1
bar=&2;
of
C++:
1
foo:foo(int bar){this->bar=&bar;}
of zoiets hebben?

Ik kan me ook even niet indenken waarom je dat zo zou doen... je maakt een alias naar iets buiten je class, is dat niet heel erg gevaarlijk? En binnen je class, waarom zou je dat als member doen?
Een reference moet zover ik weet in de member initialiser list worden geinitialiseerd.
Daarnaast gebruike je gewoon
Int a;
int& b = a;
als initialisatie voor een reference.

[ Voor 5% gewijzigd door NC83 op 17-08-2009 18:20 ]

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op maandag 17 augustus 2009 @ 18:03:
[...]
Wat had hij gedaan, constante pointers gemaakt?
Een pointer wijst naar een object, maar is zelf natuurlijk ook een object (de pointer zelf dus, en heeft als waarde de referentie naar het andere object). Objecten kunnen const zijn. Hierdoor is er een verschil in een const pointer en een pointer-naar-const (hoewel de meeste mensen het over een pointer-naar-const hebben als ze const pointer zeggen, om het maar even extra ingewikkeld te maken). Een const pointer kun je niet wijzigen, maar het object waarnaar verwezen wordt wel. Een pointer-naar-const kun je wel wijzigen, maar het object waarnaar verwezen wordt niet. Voorbeeld:
C++:
1
2
3
4
int i = 34;
const int * pointerToConst = &i; // #1
int * const constPointer = &i; // #2
const int * const constPointerToConst = &i; // #3

Bij #1 mag je de int waarnaar verwezen wordt niet wijzigen. Je kunt dus niet zeggen: *pointerToConst = 48. Wel kun je 'm naar een andere int laten wijzen, dus pointerToConst = new int(48) mag wel.
Bij #2 is het precies andersom - hier is het pointer object zelf const, maar de int waarnaar verwezen wordt niet. #3 doet allebei - zowel de pointer zelf als de int waarnaar verwezen wordt zijn const.

Als je het hebt over een const member dan is de member zelf dus const. In het geval van een pointer gaat het dan om een const pointer, en niet om een pointer to const. Een const char * ptr is dus geen const pointer.

[ Voor 14% gewijzigd door .oisyn op 17-08-2009 18:19 ]

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!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op maandag 17 augustus 2009 @ 18:03:
dan moet je... ergens (waar? in de .h of de .cpp?)
C++:
1
bar=&2;
of
C++:
1
foo:foo(int bar){this->bar=&bar;}
of zoiets hebben?
2 is geen variabele. En &bar is een pointer naar bar. Je wilt een referentie naar bar. Oftewel, gewoon 'bar'. Maar je moet het in de member initializer list doen, anders ben je te laat.
Ik kan me ook even niet indenken waarom je dat zo zou doen... je maakt een alias naar iets buiten je class, is dat niet heel erg gevaarlijk?
Het gebeurt ook niet zo vaak, en je moet garanderen dat de referentie minstens zo lang leeft als de instance van je class zelf. En bovendien werkt de default assignment operator niet meer - je kunt een reference zelf immers niet aanpassen. Geldt trouwens ook voor const members van de class :).

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Meestal als je een member hebt die ergens naar wijst is het een pointer.

References worden gebruikt om de pass by reference semantic in functies te gebruiken, dit is namelijk effiecienter dan het pass by value semantic. 4 bytes(reference is effectief een pointer) tegen over een heel object.

Daarnaast kun je een waarde aan een reference variable geven in de functie en zodoende meerdere waardes uit een functie kunt terug geven (functie param mag dan wel niet const zijn).

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 13:32:
Ik zou in deze code trouwens wel een type gebruiken als ik jou was, in dit geval wordt een unsigned integer aangenomen maar dat zou wel eens anders kunnen zijn in een andere compiler.
Ook al is het zoals oisin zegt eigenlijk per definitie altijd een int zou dat wel duidelijker zijn en leesbaarder.
unsigned is een type modifier die aangeeft dat het type wat je gebruikt geen sign bevat, dus geen plus of min.
Daarnaast is het gebruik van "this->" niet noodzakelijk aangezien dat altijd wordt toegepast in een member function. Je hebt het natuurlijk wel nodig als een van je parameters dezelfde naam heeft als een member variable.
Ja dat is meer uit gewoonte dat ik dat gedaan heb, geeft beter de intentie weer van "ik pak een argument en sla het op als member".

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 13:42:
Onzin, "unsigned" is per definitie een alias voor "unsigned int". Het is dan ook geen type modifier. Dit mag om die reden ook niet:
C++:
1
2
typedef int myint;
unsigned myint bla;
Maar een gewone alias is het toch ook niet? Want dan zou
C++:
1
unsigned int bla;
iets zijn als
C++:
1
int int bla;
syntactisch gezien?
En dan zou
C++:
1
 myint int bla;
ook moeten kunnen... dus wat voor iets is "unsigned" dan eigenlijk. Kan je dat ook niet gebruiken voor zelf klassen en typen te maken die iets met die "modifier" kunnen?
Het is natuurlijk wel raar dat de setters een signed int verwachten terwijl het vervolgens in een unsigned int opgeslagen wordt.
Ah, lol, oeps, yep, dat is niet erg zinnig nee en kan vreemd overkomen, kan best ineens unsigned ints gebruiken dan is het voor iedere gebruiker van de klasse duidelijk dat onder nul niet kan.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op maandag 17 augustus 2009 @ 20:01:
[...]

Maar een gewone alias is het toch ook niet? Want dan zou
C++:
1
unsigned int bla;
iets zijn als
C++:
1
int int bla;
syntactisch gezien?
En dan zou
C++:
1
 myint int bla;
ook moeten kunnen... dus wat voor iets is "unsigned" dan eigenlijk. Kan je dat ook niet gebruiken voor zelf klassen en typen te maken die iets met die "modifier" kunnen?
Het type "unsigned" is een alias voor het type "unsigned int", maar is weer anders dan het type "unsigned long". Een "unsigned int" zelf bestaat niet uit twee typen. Wel twee woorden, maar daar ging het niet om. En zoals ik al zei, het is geen modifie. In de standaard heet het een type specifier, en er mag maar 1 type specifier in een type voorkomen. De uitzonderingen zijn:
• const en volatile mag je overal mee combineren
• signed en unsigned kun je combineren met char, short, int en long
• short en long kun je combineren met int
• long kun je combineren met double
En het totaalplaatje vormt het uiteindelijke type. De volgende type specifier sequences refereren dus allemaal aan hetzelfde type:
short
short int
int short
signed short
short signed
signed short int
short signed int
signed int short
short int signed
int signed short
int short signed

[ Voor 35% gewijzigd door .oisyn op 17-08-2009 20:27 ]

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Daar moet dan weer wel bij worden gezegd dat data types bepaalde ranges bevatten die aan de volgende eisen moeten voldoen.
1 byte <= char (meestal 1 byte) <= short (meestal 2 bytes) <= int (meestal 4 bytes) <= long (meestal 8 bytes)
hetzelfde geldt voor float(meestal 4 bytes) <= double (meestal 8 bytes)

[ Voor 57% gewijzigd door NC83 op 17-08-2009 21:07 ]

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

char is per definitie 1 byte ;)
Overigens heb ik op alle gangbare platforms die ik ben tegengekomen nog nooit een 64 bits long gezien.

[ Voor 89% gewijzigd door .oisyn op 17-08-2009 21:21 ]

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

had GCC voor x64 geen 64bits longs? dat is een vrij gangbaar platform zover ik weet :)
dacht dat GCC ging voor LP64, en MSVS voor LLP64...

voor compleetheid, sommige C++ compilers (zowel ICC, GCC als MSVS) hebben ook nog een long long (net als standaard C), die is wel meestal 64 bits, ook in x86 mode

-niks-


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
8 Bytes = 8x8 bits = 64 bits
Op windows is long long gelijk aan uint_64

[ Voor 44% gewijzigd door NC83 op 17-08-2009 23:10 ]

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


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

MLM schreef op maandag 17 augustus 2009 @ 22:30:
had GCC voor x64 geen 64bits longs? dat is een vrij gangbaar platform zover ik weet :)
dacht dat GCC ging voor LP64, en MSVS voor LLP64...
Ah ja klopt idd. Ik was even in de war met int die op de 64 bits versies van zowel Windows als Linux 32 bits blijft.
voor compleetheid, sommige C++ compilers (zowel ICC, GCC als MSVS) hebben ook nog een long long (net als standaard C), die is wel meestal 64 bits, ook in x86 mode
long long zit ook in C++0x, dus wat dat betreft is het ook vrij veilig om 'm te gebruiken aangezien elke fatsoenlijke compiler hem toch al vroeg of laat gaat ondersteunen. De type specifier regels hebben wat dat betreft een grappige bijwerking - aangezien je de volgorde van de specifiers niet uitmaakt, mag je dus bijv. ook "long unsinged long" schrijven 8)7
NC83 schreef op maandag 17 augustus 2009 @ 23:08:
8 Bytes = 8x8 bits = 64 bits
Op windows is long long gelijk aan uint_64
Je bedoelt __int64 :) (overigens bestaan die __intN's ook voor 8, 16 en 32 bits, met de juiste aliasen voor resp. char, short en int)

[ Voor 15% gewijzigd door .oisyn op 17-08-2009 23:25 ]

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
Dit is allemaal zeer interessant, al ben ik zeer verbaasd over hoeveel er van te vertellen is :D . Met alle onderbrekingen krijg ik het hier niet zo snel gelezen als dat er antwoorden komen.
.oisyn schreef op maandag 17 augustus 2009 @ 16:25:
Het is een member, maar geen instance member. De storage is dus per class, ipv per object. Verder:
C++:
1
2
3
4
5
6
7
8
9
MyClass::MyClass()
// member initializer list
:    BaseClass(34),     
     member1(1),
     member2("hoi")
{
}

SomeStruct s = { 1, 2, 3 }; // initializer list

Dus nee, die zijn niet hetzelfde :). Die onderste variant werkt ook alleen maar voor aggregate types (classes en structs zonder zelf-gedefinieerde constructors)
Mja, op http://www.cprogramming.c...ialization-lists-c++.html hebben ze het nergens over "member" initialisation lists. Maar nu je het zegt, zo'n groep elementen is idd ook een lijst, en initialiseert ook je variabele ja. Ik ken die techniek eigenlijk alleen van arrays (en volgens mij heb ik dat alleen nog maar in java of zo gezien). Ik kan me niet voorstellen hoe je dat moet lezen in de context van een struct/klasse? Als je dan functies hebt, of al dan niet extra constructoren, of pointers... lijkt me bijzonder lastig.

En dat moet je initialiseren dan aan de hand van de volgorde dat ze gedeclareerd zijn in de .h veronderstel ik?
Als ze niet static zijn is de declaratie in de class zelf genoeg he :).
Euh... dat snap ik niet...je moet toch alles definieren? Een declaratie zonder definitie moet toch linker problemen geven (unresolved externals)?
Er is ook een instantie van die member per class instance, dus er is ook geen enkele reden om ze los in een translation unit (source file) te definieren. Pas als ze static zijn dan moet je, net als globale variabelen, ze ook definieren in een specifieke translation unit (anders heeft uiteindelijk geen enkele file de definitie van die variabele, en dan krijg je link errors)
:? voorbeeld aub...
Je hebt in elke class die member zitten (zijn eigen versie), dus... moet je ze niet los in een source file (cpp file) definieren? hoezo niet?
Wat doet dan zonder definitie...?
Je bedoelt member functions? Dat komt omdat ze impliciet inline zijn als je ze binnen een class definieert. Dit geldt overigens, itt static variabelen, ook voor static functies.
Ik dacht al dat 't zoiets was.

Dus functies die kort (maakt de lengte uit? want inline is toch vooral bedoeld voor overhead weg te halen?) worden gedefinieerd, van de aard van getters ens setters met alleen
void func(int y) {x=y} 
die je gewoon in de header laat staan, worden die niet dubbel gedefinieerd als je de .h file meerdere keren include omdat ze "impliciet" inline zijn. Vermits code geoptimaliseerd wordt door de compiler en die soms zelf inline of niet beslist kan het dus zijn dat als je het buiten de
class x{}
body zet, het "toevallig" ook kan werken (dus dat je een korte functie die hij zelf als inline heeft bevonden), zelfs als alles in de .h file staat?

Iets anders wat ik heb opgemerkt is dat hij hij die .h file include in elke "obj" compilatie eenheid, en de linker dan ineens merkt dat hij daar die .h file heeft, en op een andere plek waar die geinclude werd ook nog, en dat daar een implementatie bij zit. Als je die file niet .h maar .cpp noemt, dan gaat hij die als een compilatie eenheid bekijken blijkbaar want dan krijg je ineens daar ook een obj file van en ook al include je die maar 1 keer, dan krijg je al dezelfde fout.
Dus, heb ik gelijk als ik zeg dat .h files en .cpp files niet gelijk behandeld worden? Ik was in den beginne onder de indruk dat de naam van de files weinig te betekenen had en meer voor de programmeur dan voor de compiler bedoeld was en dat je ze net zo goed .bmp of .koffiekoek kon heten.
En klopt het ook dat "translation units" alleen op cpp files slaan dan, inclusief hun geïnclude .h files?


Als je een functie in de klasse definieert, dan is die impliciet inline en is dat geen probleem meer
Dus alles binnen
C++: bla.h
1
2
3
class bla {
void func(){}
}

>> die void func is nu impliciet inline en zal geen problemen geven

Als ik nu echter, in de .h file, dit zou doen :
C++: bla.h
1
2
3
4
class bla {
void func();
}
void bla::func(){}

Dan crashed de zaak? - Tenminste, van de moment dat je die .h file op 2 plaatsen gebruikt.
Dit is dus niet identiek aan het vorige? Want ik dacht dat door classname:: er voor te zetten je eigenlijk terug "in" de klasse bezig was, ik dacht dat dat gewoon een andere manier van noteren was dan er terug een class blok rond te zetten...

Maar dan snap ik het doel niet meer van #pragma once of die include guards ...
Als je per c++ file translation units hebt, en die "include only once" enkel binnen elke translation unit werkt, dan ga je toch nooit 2 keer hetzelfde includen? Want wie zet er nu 2 keer include zelfde file onder elkaar? Ik had altijd gedacht dat dat was omdat je in de ene .cpp file dingen include, en daarna in de andere dezelfde dingen, en dat bij het compileren alles gewoon 1 gigantische tekst file werd...niet dat er aparte blokken werden gevormd...

En als ik het nu opsplits, dus die laatste regel in een .cpp file zet
C++: bla.h
1
2
3
class bla {
void func();
}
C++: bla.cpp
1
void bla::func(){}

is't opgelost
@ post hierboven: klopt helemaal :). Methoden die de observable state van het object niet veranderen kun je sowieso beter altijd const maken. Dus dat geldt typisch ook voor getters :)
Eh, ja maar moet het ook? Kan het werken zonder? Ik vraag het omdat dat impliceert dat je best zoveel mogelijk methoden const maakt, om te verhinderen dat ze niet meer werken als je object ooit eens per ongeluk const status verkrijgt.

[ Voor 0% gewijzigd door Rygir op 18-08-2009 03:22 . Reden: typo ]


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 23:08:
8 Bytes = 8x8 bits = 64 bits
Op windows is long long gelijk aan uint_64
Dat doet me ergens anders aan denken...

Ik las dat je met fstreams char waarden wegschrijft, dus karakters. Ik dacht eerst dat dat 128 was, maar dat is omdat dat een signed char is, dus je hebt eigenlijk 256 waarden, dus dat is 8 bits, een char. 7 bits had ik heel vreemd gevonden.

Nu, voor mijn toepassing werk ik echt met losse bits, dus bit per bit, ik heb dan ook een bitstream klasse gemaakt en daarmee kan ik netjes idd char per char, dus per 8 bits uit die klasse uitlezen zogezegd.

Maar dat wil wel zeggen dat achteraan mijn bestand tot maximaal 7 overbodige bits kunnen staan, die ik niet weg krijg? Niet dat ik daar dood van ga, maar dat lijkt me een vrij domme beperking? Heb ik iets over het hoofd gezien, of is het onmogelijk om bestandsgroottes op bit niveau te bepalen en is dat altijd per byte?

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:02
Je hebt een heleboel vragen, wat begrijpelijk is want C++ is niet de meest makkelijke taal.

Een belangrijke regel is de Wikipedia: One Definition Rule. Als je die begrijpt, weet je ook het antwoord op een heleboel vragen die je stelt. :)

Ook stel ik voor dat je de http://www.parashift.com/c++-faq-lite leest, inclusief alle links in die faq :). De verwarring tussen declaratie/definitie wordt ook daar uit de doeken gedaan.

[edit]
want inline is toch vooral bedoeld voor overhead weg te halen
Inline dient ervoor om aan de compiler te vertellen dat de definitie van bv een functie mag worden gebruikt in de resulterende code, ipv een echte function call. Om dat te doen hebben de meeste compilers echter wel ook die definitie nodig op dat punt. Of de compiler ook echt die functie gaat inlinen, is maar de vraag trouwens.
Dus, heb ik gelijk als ik zeg dat .h files en .cpp files niet gelijk behandeld worden?
Een compiler zal waarschijnlijk een .cpp bestand default gaan behandelen als een source file, alhoewel je inderdaad ook een .sinterklaas bestand als C++ source zou kunnen gaan behandelen, zolang je de compiler maar verteld wat ie moet doen. De standaard zal hierover niet veel zeggen vermoed ik.
Maar dan snap ik het doel niet meer van #pragma once of die include guards ...
Die vraag heb ik in een ander topic van je al beantwoord. Als je het build proces van een C++ translation unit bergijpt, begrijp je ook waarom die guards daar staan.
Eh, ja maar moet het ook?
Nee het moet niet. Als je het wel doet echter is de compiler in staat tot betere optimalisaties mbt tot die functies/variabelen.

[ Voor 52% gewijzigd door farlane op 18-08-2009 00:43 ]

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
Ik heb trouwens nog een vraag gerelateerd aan het oorspronkelijke probleem :

Gaat dit :
C++: bla.h
1
2
3
4
5
6
7
Class foo {}

Class bla {
public:
  foo var;
 int myint;
}

ok tot zover gaat nog (of ik moet iets over het hoofd zien), maar dan moet je die in de constructor initialiseren, die foo, via
C++: bla.cpp
1
2
bla::bla():var(),myint=2 /*mag dit zo, of MOET het ook myint(2) zijn, wat ik in de cursus las*/
{}

Het probleem voor mij is nu : kan je die daarna nooit meer opnieuw laten initialiseren?
maw, Je kan daar geen andere "foo" object aan koppelen?
Het probleem is namelijk dat ik een foo object wel kan initialiseren, maar dat in mijn klasse die foo een constructor heeft met parameters die intern een array aanmaken. En zoals je weet kan je arrays niet growen, dus als ik later merk dat mijn "foo" te klein is, dan kan ik de member foo van bla niet meer "vergrootten" want die is zo geinitialiseerd en niet anders.
Ben ik dan verplicht van foo een pointer te maken? Die moet ik gewoon via de constructor initialiseren met new dan? (en in de destructor met delete).




Dat brengt me weer bij iets anders waar ik me "zorgen" over maak, als ik references zou gebruiken, dus ipv gewoon
foo var
in de code hierboven
&foo var 
, hoe zit dat dan met de destructor, moet ik die dingen gaan deleten? delete die die vanzelf, en if so, wat als die dan verwijzen naar iets buiten de klasse?

En wat als ik een pointer heb, en ik heb "new" gedaan, en er een object aan toegewezen, en nu heb ik via parameter of via nog een new een nieuw object van dat type, en ik wijs dat aan die pointer toe. moet ik dan eerst delete doen op die pointer alvorens de nieuwe toe te wijzen, of heeft die vanzelf door dat die andere weg moet? Want nu ik er zo over nadenk, ik heb nog maar weinig, zoniet geen code gezien met delete midden in de code, alleen maar in destructors...

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 16:39:
Daarnaast is het zo dat je static const int in een class in de header kunt initialiseren, alle andere types dan int moeten in de CPP worden geinitialiseerd.
Yep, precies, dat is waarom ik er nooit eerder mee werd geconfronteerd, en dat zijn ook de voorbeelden die overal besproken worden. Daar weet je dus niks mee want dat is eigenlijk net de uitzondering... daarmee dat ik in geen benul had van dat het includen van headers met definties problemen kon geven.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op dinsdag 18 augustus 2009 @ 00:00:
Mja, op http://www.cprogramming.c...ialization-lists-c++.html hebben ze het nergens over "member" initialisation lists.
Dat zal best. Maar ik gebruik liever de terminologie zoals die in de standaard beschreven staat ;)
En dat moet je initialiseren dan aan de hand van de volgorde dat ze gedeclareerd zijn in de .h veronderstel ik?
Jup. Althans, je zegt hier "in de .h", maar het gaat natuurlijk om de definitie van de class of struct. Waar die staat doet er niet echt toe :)
Euh... dat snap ik niet...je moet toch alles definieren? Een declaratie zonder definitie moet toch linker problemen geven (unresolved externals)?
Feitelijk is een non-static variabeledeclaratie in een class ook meteen een definitie. Maar je snapt toch wel waarom je een static variabele wel buiten de class in een translation unit moet definieren, en een instance variabele niet? Een static variabele heeft een vast adres. Er is er 1 van, en die leeft dus *ergens*. Waar die leeft geef je aan door 'm te definieren. Een instance (non-static) variabele niet, omdat er een instantie van die variabele bestaat per object van die class. En als er geen object van die class bestaat is die variabele er ook niet.
C++:
1
2
3
4
struct Foo
{
    int bar;
};

'bar' is op zichzelf niets. Je kunt niet Foo::bar = 4 doen oid. Je moet een Foo constructen, bijvoorbeeld op de stack. Als je dat doet, dan maakt de compiler genoeg ruimte vrij om ook die 'bar' binnen de Foo instantie op te slaan.
Dus functies die kort (maakt de lengte uit? want inline is toch vooral bedoeld voor overhead weg te halen?) worden gedefinieerd, van de aard van getters ens setters met alleen
void func(int y) {x=y} 
die je gewoon in de header laat staan, worden die niet dubbel gedefinieerd als je de .h file meerdere keren include omdat ze "impliciet" inline zijn.
Juist. Maar inline is sowieso maar een hint. Als een compiler een functiedefinitie kent, kan hij zelf besluiten of hij inlinet. En met moderne compilers wordt code zelfs pas gegenereerd tijdens het linken, dus hij kan dan ook functiedefinities zien uit andere translation units en dan alsnog besluiten om te inlinen of niet.
Iets anders wat ik heb opgemerkt is dat hij hij die .h file include in elke "obj" compilatie eenheid, en de linker dan ineens merkt dat hij daar die .h file heeft, en op een andere plek waar die geinclude werd ook nog, en dat daar een implementatie bij zit. Als je die file niet .h maar .cpp noemt, dan gaat hij die als een compilatie eenheid bekijken blijkbaar want dan krijg je ineens daar ook een obj file van en ook al include je die maar 1 keer, dan krijg je al dezelfde fout.
Dus, heb ik gelijk als ik zeg dat .h files en .cpp files niet gelijk behandeld worden? Ik was in den beginne onder de indruk dat de naam van de files weinig te betekenen had en meer voor de programmeur dan voor de compiler bedoeld was en dat je ze net zo goed .bmp of .koffiekoek kon heten.
Klopt. Het is ook niet de compiler die dit doet, maar de IDE. Die zal files met .cpp herkennen als C++ source files, en die dus ook door de compiler gooien. Kan nog steeds als je ze .koektrommel noemt, maar dat zul je dan even tegen je IDE moeten zeggen.
En klopt het ook dat "translation units" alleen op cpp files slaan dan, inclusief hun geïnclude .h files?
Een translation unit is in de regel idd een gepreprocessde .cpp file, dus waarin alle includes al verwerkt zijn. Het is het bestand wat je aan de compiler voert.
Als je een functie in de klasse definieert, dan is die impliciet inline en is dat geen probleem meer
Dus alles binnen
C++: bla.h
1
2
3
class bla {
void func(){}
}

>> die void func is nu impliciet inline en zal geen problemen geven

Als ik nu echter, in de .h file, dit zou doen :
C++: bla.h
1
2
3
4
class bla {
void func();
}
void bla::func(){}

Dan crashed de zaak?
Er crasht niets, maar je overtreedt de One Definition Rule omdat er meerdere definities van die functie bestaan binnen je programma. Je kan het oplossen door bla::func() alsnog als inline te definieren buiten de class :)
Maar dan snap ik het doel niet meer van #pragma once of die include guards ...
Als je per c++ file translation units hebt, en die "include only once" enkel binnen elke translation unit werkt, dan ga je toch nooit 2 keer hetzelfde includen? Want wie zet er nu 2 keer include zelfde file onder elkaar?
Stel je hebt foo.cpp, die include "foo.h" en "bar.h", maar foo.h en bar.h includen beide <string>, dan wordt <string> dus twee keer geinclude, maar toch staan ze niet na elkaar. Dit ga je tegenkomen zodra je bijv. veel classes hebt die van elkaar afhankelijk zijn, of gewoon zoals in dit voorbeeld bij de standaard headers die op veel plekken gebruikt worden.
Eh, ja maar moet het ook?
Natuurlijk moet het niet. Als jij niet wilt dat jouw methoden werken op const objecten dan moet je dat niet doen. Maar in de regel wil je het wel. Dit noemt men const-correctheid. Een object is ook niet "per ongeluk" const, maar is dat met een reden. Als een functie een referentie naar een object wilt dat hij niet aan gaat passen, dan vraagt die functie dus om een const reference naar dat object. Dit is handig omdat iedereen die zelf een referentie naar dat const object heeft dan weer die functie aan kan roepen.

Feitelijk zou dit ook moeten gelden voor volatile en const volatile, maar vrijwel niemand definieert z'n objecten ooit als volatile dus dat is de moeite niet waard.

Rygir schreef op dinsdag 18 augustus 2009 @ 00:04:
Maar dat wil wel zeggen dat achteraan mijn bestand tot maximaal 7 overbodige bits kunnen staan, die ik niet weg krijg? Niet dat ik daar dood van ga, maar dat lijkt me een vrij domme beperking? Heb ik iets over het hoofd gezien, of is het onmogelijk om bestandsgroottes op bit niveau te bepalen en is dat altijd per byte?
Pff, die 7 bits zijn je probleem niet. Vraag eens de properties van een willekeurige file in Windows op. Je ziet daar een "actual size" en een "size on disk". Die size on disk is typisch de filegrootte gealigned op de eerstvolgende 4 kilobyte boundary. Dus ook al wil je 1 bit opslaan in een file, hij wordt alsnog 4 kilobyte.

farlane schreef op dinsdag 18 augustus 2009 @ 00:22:
Nee het moet niet. Als je het wel doet echter is de compiler in staat tot betere optimalisaties mbt tot die functies/variabelen.
Const correctness heeft vrijwel geen invloed op optimalisaties. Het feit dat het object waarnaar gerefereerd wordt const is wil niet zeggen dat dat object niet aangepast kan worden na een aanroep van een functie waarvan je de interne werking niet kent. En als je die interne werking wel kent dan kun je ook bepalen of dat object al dan niet aangepast wordt (wat alsnog lastig is wegens aliasing). De enige mogelijke optimalisatie is als je het object zelf als const definieert.

Rygir schreef op dinsdag 18 augustus 2009 @ 00:45:
Ik heb trouwens nog een vraag gerelateerd aan het oorspronkelijke probleem :
Tja, je vragen worden wel erg basic. Het lijkt me handiger als je gewoon een goed boek door gaat nemen.

De notatie van een reference is trouwens "foo& var", niet "&foo var".

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!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 18:02:
Precies als je er meer over wilt weten moet je de "gang of three rule" eens opzoeken
Hmm, dat klinkt als wat ik een paar weken terug heb gebruikt in m'n matrix klasse :
C++:
1
2
3
4
   // Based on the Law Of The Big Three:
  ~Matrix();
   Matrix(const Matrix& m);
   Matrix& operator= (const Matrix& m);
C++ copy constructor doet een shallow copy, dus als je pointers in je classe hebt krijgen die dezelfde waarde. De pointer zal dus naar het zelfde object als het origineel wijzen. Je krijgt hier problemen doordat als je het origineel vernietigd inclusief het object waar de pointer daarin verwijst. De pointer in de copy zal dan naar een stuk geheugen wijzen dat niet noodzakelijker wijze het object is dat je verwacht.
Dankzij de destructor dus, en dan is dat niet zomaar een "onverwacht" object, dat stuk geheugen is volledig ongedefinieerd en vrij en kan dus alles in staan...

Doet me trouwens denken aan een vreemde observatie : Als ik een array aanmaak van integers, dan worden die normaal niet op nul geinitialiseerd. Nu heb ik echter gemerkt dat die altijd 250 zijn... elke keer ik het programma uitvoer waren alle waarden hetzelfde, en op meerdere PC's... voor ongedefinieerd te zijn vond ik dat wel heel erg consistent, iemand een idee waarom? (of 205 kan ook, ben ik ff niet zeker van)
Een reference is een alias voor een variable en moet altijd een waarde hebben, dit betekent dat je een reference kan gebruiken ipv een variable.
"Moet altijd een waarde hebben"... ik moet m'n hoofdstuk van references eens herlezen blijkbaar... bedoel je dat het altijd naar iets moet wijzen en geen nullpointer mag zijn of zo? En ik weet dat je ze als alias gebruiken kan, maar uiteindelijk is & toch de operator om het adres van iets op te vragen. Ik kan ze dus wel in een functie gebruiken, maar het gedrag ervan ivm geheugenbeheer als het members zijn is me niet duidelijk...maar goed dat heb ik nu niet direct nodig dus dat zoek ik wel eens op.

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 18:17:
... in de member initialiser list worden geinitialiseerd.
Aha.
Daarnaast gebruike je gewoon
Int a;
int& b = a;
als initialisatie voor een reference.
Ja, zo ken ik het ook, om een alias voor a te hebben.

Nu ben ik me eigenlijk aan het afvragen, buiten voor typcomfort, waarom zou je aliassen gebruiken? Als je aan het origineel kan om te initialiseren kan je toch net zo goed daar mee werken... (hmm sorry als dit onnozele vragen zijn, ik heb nog niet veel ervaring met reference variabelen opgedaan en er nog geen nood aan gehad).

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op dinsdag 18 augustus 2009 @ 01:31:
Doet me trouwens denken aan een vreemde observatie : Als ik een array aanmaak van integers, dan worden die normaal niet op nul geinitialiseerd. Nu heb ik echter gemerkt dat die altijd 250 zijn... elke keer ik het programma uitvoer waren alle waarden hetzelfde, en op meerdere PC's... voor ongedefinieerd te zijn vond ik dat wel heel erg consistent, iemand een idee waarom? (of 205 kan ook, ben ik ff niet zeker van)
Het was waarschijnlijk een array van chars, en die waarde is idd 205, ofwel 0xcd, wat de VC++ code is voor "dit geheugen is niet geïnitialiseerd". Dat zie je voornamelijk in debug builds. Je hebt wel meer van die codes, zoals 0xdd (dacht ik) voor "dit geheugen is vrijgegeven". Soms zie wat slimmer bedachte codes als 0xdeadbeef of 0xbaadf00d :). Wij gebruiken op 't werk 0xbaddaf1d, die je tegenkomt als de decompressiecode van m'n collega David niet goed werkt :Y)

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op dinsdag 18 augustus 2009 @ 01:35:
[...]
Aha.

[...]

Ja, zo ken ik het ook, om een alias voor a te hebben.

Nu ben ik me eigenlijk aan het afvragen, buiten voor typcomfort, waarom zou je aliassen gebruiken? Als je aan het origineel kan om te initialiseren kan je toch net zo goed daar mee werken... (hmm sorry als dit onnozele vragen zijn, ik heb nog niet veel ervaring met reference variabelen opgedaan en er nog geen nood aan gehad).
Als je een classe hebt die zeg maar 0.5 meg groot is het sneller is om een allias een functie in te sturen omdat die maar 4 bytes (grote van een pointer) is. Zelfde geldt voor return types als je een member variable terug geeft. http://en.wikipedia.org/w...%2B%29#Uses_of_references

Wat ik bedoelde met references moet een waarde hebben is dat je niet dit kan schrijven:
C++:
1
2
3
4
5
int& a; //Compile error

//Compiler output
//1>e:\sdk\dx_engine\window.cpp(90) : error C2143: syntax error : missing ';' before '&'
//1>e:\sdk\dx_engine\window.cpp(90) : error C2059: syntax error : ';'


Een andere deleted memory flag die je wel eens tegen komt is 0xfefefefe, deze kom je geloof ik tegenbij objecten met een virtual function table waarbij de table deze waarde heeft. Virtual function table is de tabel waarin een object pointer naar inherited functions bewaart.

[ Voor 11% gewijzigd door NC83 op 18-08-2009 01:59 ]

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
yep, yep ik ben volledig mee, ik dacht wel dat hij dat had gedaan.

Nu we het over pointers naar constante objecten hebben heb ik weer een nieuwe vraag.. :D
Wat is de invloed van const op een object : als ik een object const maak, zijn dan alle members ervan "read only" geworden, ook al kan ik er gewoon aan? Dus als die member objecten heeft, dan zijn die ook ineens const geworden, zowel de pointer naar dat object, als het object zelf? Of is het mogelijk dat je via een constante verwijzing, al dan niet via pointer, naar een object in dat object toch nog dingen kan wijzigen onder omstandigheden( uitgezonderd mutable enzo, want dan is 't voor expres)?
Voorbeeld:
C++:
1
2
3
4
int i = 34;
const int * pointerToConst = &i; // #1
int * const constPointer = &i; // #2
const int * const constPointerToConst = &i; // #3

Bij #1 mag je de int waarnaar verwezen wordt niet wijzigen. Je kunt dus niet zeggen: *pointerToConst = 48. Wel kun je 'm naar een andere int laten wijzen, dus pointerToConst = new int(48) mag wel.
Bij #2 is het precies andersom - hier is het pointer object zelf const, maar de int waarnaar verwezen wordt niet. #3 doet allebei - zowel de pointer zelf als de int waarnaar verwezen wordt zijn const.
Yep,yep dat stond ook op http://duramecho.com/ComputerInformation/WhyHowCppConst.html - wat ik een zeer verhelderende tekst vond, behalve dan het stuk waarvoor ik deze topic ben gestart.

Daar zeggen ze dat const op het element vlak links er van slaat, behalve als er niks links is (dus het staat als eerste op een regel zogezegd), dan is het het element er langs.
C++:
1
int const * constPointer = &i;
is dan ook equivalent met voorbeel #2 .oisyn hierboven.
Als je het hebt over een const member dan is de member zelf dus const. In het geval van een pointer gaat het dan om een const pointer, en niet om een pointer to const. Een const char * ptr is dus geen const pointer.
Eh?
const char * ptr
is toch net wel een const pointer en geen pointer-to-const?



Hoe zet ik een paar woorden code inline in een zin in code-achtige opmaak?

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

Rygir schreef op dinsdag 18 augustus 2009 @ 01:58:
Eh?
const char * ptr
is toch net wel een const pointer en geen pointer-to-const?
Juist wel. 'ptr' wijst naar een const char. De char mag je dus niet wijzigen. De pointer zelf wel. De const slaat dus op 'char', niet op 'ptr'

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!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op dinsdag 18 augustus 2009 @ 01:58:
[...]
yep, yep ik ben volledig mee, ik dacht wel dat hij dat had gedaan.

Nu we het over pointers naar constante objecten hebben heb ik weer een nieuwe vraag.. :D
Wat is de invloed van const op een object : als ik een object const maak, zijn dan alle members ervan "read only" geworden, ook al kan ik er gewoon aan? Dus als die member objecten heeft, dan zijn die ook ineens const geworden, zowel de pointer naar dat object, als het object zelf? Of is het mogelijk dat je via een constante verwijzing, al dan niet via pointer, naar een object in dat object toch nog dingen kan wijzigen onder omstandigheden( uitgezonderd mutable enzo, want dan is 't voor expres)?
Als je een object const maakt zijn alle velden in die instance constant en je kunt enkel const member functies uitvoeren van deze instance. Const member functies hebben de volgende vorm:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Vector2
{
public:
    Vector2();
[...]

    float dot (const Vector2& v) const; //const member function
    Vector2 multiply (float scalar) const; //const member function
    Vector2 add(const Vector2& v) const; //const member function
    bool equal(const Vector2& v) const; //const member function

    float x() const {return m_x; }  //const member function
    float y() const {return m_y; }  //const member function
protected:
private:
    float m_x, m_y;
    static const float EQUALPRECISION2;
};


Const member functions verandere de state van het object niet. De const verteld de compiler enkel dat deze functie ook van een const object kan worden uitgevoerd. Deze code laat je trouwens ook een voorbeeld van pass by reference zien in de dot, multiply, add en equal functies.

Het heeft ook een nuttige functie als readability, het geeft namelijk meteen weer dat er geen state change in die functie zal plaats vinden (waardoor je voor een API niet meer als de header nodig hebt). Zo ook het invoeren van const functie parameters verteld de gebruiker van de functie dat de waarde die wordt ingegeven niet zal veranderen.(voor meer zie const correctness)

[ Voor 13% gewijzigd door NC83 op 18-08-2009 02:10 ]

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 18:29:
2 is geen variabele. En &bar is een pointer naar bar. Je wilt een referentie naar bar. Oftewel, gewoon 'bar'. Maar je moet het in de member initializer list doen, anders ben je te laat.
Wat die 2 betreft, ik had al zo'n vermoeden, ben blij dat je het opheldert. Ik was half aan het hopen dat hij die 2 een plekje geheugen had toegekend tijdens het compileren en ik er op deze manier dan een naam aan gaf. Het equivalent van
C++:
1
int bar=2;
dus eigenlijk...

Maar als ik een een gewoon argument binnen krijg, moet ik dan niet &bar gebruiken om het toe te kennen aan een reference variabele? ... je gaat toch het adres opslaan in een nadien niet-wijzigbare alias?
C++:
1
2
3
void func(int bar, int bal){
int &foo = &bar;//dit bedoel ik, of moet het int &foo=bar; zijn?
&foo=(&)bal; //dit mag in ieder geval niet he? references zijn const, dus ongeacht de & operator bij bal.
Het gebeurt ook niet zo vaak, en je moet garanderen dat de referentie minstens zo lang leeft als de instance van je class zelf. En bovendien werkt de default assignment operator niet meer - je kunt een reference zelf immers niet aanpassen. Geldt trouwens ook voor const members van de class :).
Dat verklaart veel :) .

Maar ik moet de syntax van die reference variabelen nodig herbekijken...als jij zegt dat de assignment operator dan "bezet" is, dan wil dat zeggen dat in mijn vorige voorbeeld het nooit "&foo=" is maar gewoon "foo=" en je daarmee de referentie aanpast, en niet de inhoud waarnaar gerefereerd wordt...zoals bij pointers...
Goed punt dat bij const members de assignment operator verknoeid is :) .

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Als je een assignment op een reference doet pass je infeite de waarde aan waarnaar gewezen wordt dus:

int x = 0;
int& b = x;
b = 5;

x is nu 5

pointers en references, ik vindt dit zelf trouwens nog steeds een erg nuttige site als ik snel iets moet opzoeken.

[ Voor 37% gewijzigd door NC83 op 18-08-2009 02:21 ]

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 18:40:
Meestal als je een member hebt die ergens naar wijst is het een pointer.

References worden gebruikt om de pass by reference semantic in functies te gebruiken, dit is namelijk effiecienter dan het pass by value semantic. 4 bytes(reference is effectief een pointer) tegen over een heel object.
Yep, yep, dat is wat ik bedoelde met dat een reference toch eigenlijk een pointer is.
C++:
1
2
void func(bar& var){} 
void func2(bar* var){} 
geven voor zover ik weet allebei enkel een pointer door, dezelfde pointer zelfs (mits je als parameter dezelfde variabele doorgeeft aan beide functies natuurlijk). Het zit hem er vooral in dat je binnen de functie dan niet de hele tijd je variabele moet dereferencen met * :) . Dit is het gebruik dat ik ken.
Daarnaast kun je een waarde aan een reference variable geven in de functie en zodoende meerdere waardes uit een functie kunt terug geven (functie param mag dan wel niet const zijn).
Yep, net zoals in Java trouwens, daar is dat de enige manier om meerdere return waardes te hebben (ok daar zijn het objecten, maar je geeft uiteindelijk altijd de pointers naar die objecten door in java, daar kan je een object niet dupliceren zonder zelf eerst een copy method te maken).

Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
Rygir schreef op dinsdag 18 augustus 2009 @ 02:19:
[...]
Yep, yep, dat is wat ik bedoelde met dat een reference toch eigenlijk een pointer is.
C++:
1
2
void func(bar& var){} 
void func2(bar* var){} 
geven voor zover ik weet allebei enkel een pointer door, dezelfde pointer zelfs (mits je als parameter dezelfde variabele doorgeeft aan beide functies natuurlijk). Het zit hem er vooral in dat je binnen de functie dan niet de hele tijd je variabele moet dereferencen met * :) . Dit is het gebruik dat ik ken.

[...]

Yep, net zoals in Java trouwens, daar is dat de enige manier om meerdere return waardes te hebben (ok daar zijn het objecten, maar je geeft uiteindelijk altijd de pointers naar die objecten door in java, daar kan je een object niet dupliceren zonder zelf eerst een copy method te maken).
In C++ is dat ook de enige manier omdit te doen, tenzij je meerdere waardes van het zelfde type wil terug geven dan kan je ook een pointer naar een array terug geven. Maar dat is geen goed idee omdat je geen idee hebt hoe lang dat array is. Als een functie van mij een array terug geeft doe ik dat meestal op de volgende manier

C++:
1
2
3
4
5
6
7
8
9
10
11
12
int* returnAnArray(uint& size)
{
    //Do calculations here and create array
    size = sizeOfArray;
    return arrayVar;
}

//een betere manier is, als je STL gebruikt
std::vector<int> returnArray()
{
    return std::vector<int>();
}


Een std::vector weet namelijk hoe groot hij is en je geeft hier in feite een vector object terug dat te gebruiken is als een array.

[ Voor 18% gewijzigd door NC83 op 18-08-2009 02:27 ]

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


Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 20:05:
Het type "unsigned" is een alias voor het type "unsigned int",
Dus... er zijn eigenlijk 2 "unsigned"'s gedefinieerd, eentje is een type specifier, en eentje is een alias voor unsigned int (een type definition dinges of hoe heet dat weer)?
maar is weer anders dan het type "unsigned long". Een "unsigned int" zelf bestaat niet uit twee typen.
Dat is net wat ik niet wou beweren, omdat ik weet dat dat niet kan. Ik wou net illustreren dat unsigned toch iets anders moet zijn dan puur een alias voor unsigned int.
Wel twee woorden, maar daar ging het niet om. En zoals ik al zei, het is geen modifie. In de standaard heet het een type specifier, en er mag maar 1 type specifier in een type voorkomen.
Ik denk dat dat is wat ik wou weten, dat het een type specifier is...
De uitzonderingen zijn:
<...>
hehehehe :) mooi overzicht.

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op maandag 17 augustus 2009 @ 21:02:
Daar moet dan weer wel bij worden gezegd dat data types bepaalde ranges bevatten die aan de volgende eisen moeten voldoen.
1 byte <= char (meestal 1 byte) <= short (meestal 2 bytes) <= int (meestal 4 bytes) <= long (meestal 8 bytes)
hetzelfde geldt voor float(meestal 4 bytes) <= double (meestal 8 bytes)
Ik wist niet dat daar verplichtingen rond waren... wil dat dan ook zeggen dat, inclusief type specifiers, ze niet buiten die marges mogen gaan?

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 21:05:
char is per definitie 1 byte ;)
Overigens heb ik op alle gangbare platforms die ik ben tegengekomen nog nooit een 64 bits long gezien.
Daar zeg je zo iets... zou op een 64 bits processor de int niet 64 ipv 32 bit moeten zijn?

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op dinsdag 18 augustus 2009 @ 01:26:
[...]

Jup. Althans, je zegt hier "in de .h", maar het gaat natuurlijk om de definitie van de class of struct. Waar die staat doet er niet echt toe :)
I O+ uw volledig- & nauwkeurigheid ! :)

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op maandag 17 augustus 2009 @ 23:22:
Ah ja klopt idd. Ik was even in de war met int die op de 64 bits versies van zowel Windows als Linux 32 bits blijft.
Dat bedoelde ik dus, dat die niet naar 64 bit gaan zoals toen we van 16bit os DOS naar 32 bit OS gingen... tenslotte zit je processor nu met de int, die overal gebruikt wordt, maar op halve kracht te werken... de overige 32 bits worden niet gebruikt voor zover ik weet... Ik veronderstel dat als je een bool netjes als alleen nul en 1 (in C mag het alles zijn, het maakt alleen uit of nul of niet nul is) gebruikt, je eigenlijk bij elke berekening 31 tot 63 bits "verspilt"... hij kan die registers waar die gegevens in zitten immers niet gebruiken voor andere berekeningen?
De type specifier regels hebben wat dat betreft een grappige bijwerking - aangezien je de volgorde van de specifiers niet uitmaakt, mag je dus bijv. ook "long unsinged long" schrijven 8)7
Dat klinkt wat mij betreft logischer dan pakweg long long unsigned.
Je bedoelt __int64 :) (overigens bestaan die __intN's ook voor 8, 16 en 32 bits, met de juiste aliasen voor resp. char, short en int)
Het lijkt me dat je die moet gebruiken voor weg te schrijven naar bestanden en het netwerk, omdat je niet weet welk platform het later terug gaat openen en/of lezen? Of wacht... die kunnen nog altijd big endian en little endian zijn.... daar heb je die functies voor... ben de naam ff kwijt...

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
farlane schreef op dinsdag 18 augustus 2009 @ 00:22:
Een belangrijke regel is de Wikipedia: One Definition Rule. Als je die begrijpt, weet je ook het antwoord op een heleboel vragen die je stelt. :)
Ik heb die pagina gelezen, en nog andere... ik begrijp wel dat er, simpelweg, maar 1 defintie van 1 naam mag zijn, dat is ook logisch omdat hij anders niet weet waar het naar verwijst.

Mijn vragen vloeien eerder voort uit het feit dat het zo'n beetje is als Frans lezen, ik versta het wel, maar alle nuances ontgaan me. Daarom dat ik zo "grijze gebieden" heb waar ik niet weet of ik de regel overtreed; zoals dat van of void bla::func(); niet equivalent is met class bla {void func();} (allebei een declaratie ja). Ik dacht dat dat zo was als bij namespaces, dat je die kon uitbreiden verderop, met een statement van 1 regel in plaats van een body.
Ook stel ik voor dat je de http://www.parashift.com/c++-faq-lite leest, inclusief alle links in die faq :). De verwarring tussen declaratie/definitie wordt ook daar uit de doeken gedaan.
Dat is een site die ik veel raadpleeg ja :) . Al zal ik niet beweren dat ik alle links al heb gelezen :D .
Maarre, had ik ergens declaratie/definitie verkeerd gebruikt dan? Volgens mij weet ik het verschil daartussen wel...
Inline dient ervoor om aan de compiler te vertellen dat de definitie van bv een functie mag worden gebruikt in de resulterende code, ipv een echte function call. Om dat te doen hebben de meeste compilers echter wel ook die definitie nodig op dat punt. Of de compiler ook echt die functie gaat inlinen, is maar de vraag trouwens.
Ja dat is wat ik bedoelde, dat je de overhead van de function calls elimineert als de functie erg kort is. Dus dat je de functie invoegt op die plek. Lijkt me ook vrij logisch dat om de definitie in te voegen je de definitie nodig hebt? Als er een compiler is die zonder kan ben ik benieuwd hoe...
En ja het inline keyword is meer een "suggestie", zo heb ik geleerd. Vandaar ook mijn eerdere vraag van of dat niet soms fout kan gaan, afhankelijk van de beslissing van de compiler.
Die vraag heb ik in een ander topic van je al beantwoord. Als je het build proces van een C++ translation unit bergijpt, begrijp je ook waarom die guards daar staan.
Dat klopt ja, dat ander topic is een beetje op de achtergrond geraakt omdat ik met dit probleem zat en er zoveel respons en nuances bij kwamen.

Ik heb begrepen uit de post van .oisyn dat die translation units ruwweg de cpp's zijn, met hun geinclude headers, en dat in die headers dezelfde headers ook nog eens kruislings kunnen geinclude zijn en dan kan het idd wel voorkomen.
Nee het moet niet. Als je het wel doet echter is de compiler in staat tot betere optimalisaties mbt tot die functies/variabelen.
Aha, interessant, die optimalisaties! (maar - en oisyn heeft het beantwoord, ik doelde op of de functie mocht aangesproken worden als het object const was, maar de functie niet).

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op dinsdag 18 augustus 2009 @ 01:26:
Feitelijk is een non-static variabeledeclaratie in een class ook meteen een definitie.
:S
Dit klinkt echt vreemd... een declaratie die een definitie is...
Maar je snapt toch wel waarom je een static variabele wel buiten de class in een translation unit moet definieren, en een instance variabele niet? Een static variabele heeft een vast adres. Er is er 1 van, en die leeft dus *ergens*. Waar die leeft geef je aan door 'm te definieren. Een instance (non-static) variabele niet, omdat er een instantie van die variabele bestaat per object van die class. En als er geen object van die class bestaat is die variabele er ook niet.
:x
ik snap wat static betekent...
maar -voor zover ik tot nu toe begrijp- maakt het toch alleen uit waar je iets definieert voor je include gedoe zodat je geen duplicaten krijgt? Meer bepaald dat je alles in de cpp en niet de header definieert... dussss... die static buiten de class, in de cpp snap ik nog... als het niet in de cpp is maar inde .h zal hij ook nog in de translation unit belanden, maar riskeer je duplicaten... maar waarom die nu buiten de class moet staan...hmm. Dat is met m'n java achtergrond, daar staat alles in je class :p . Dus ik zie er geen graten in waarom een static niet "binnen" je class mag gedefinieerd worden, vanuit syntactisch oogpunt...
Dat die uiteraard al bestaat voor er instanties van de class zijn vind ik iets wat de compiler moet doen :p .
C++:
1
2
3
4
struct Foo
{
    int bar;
};

'bar' is op zichzelf niets. Je kunt niet Foo::bar = 4 doen oid. Je moet een Foo constructen, bijvoorbeeld op de stack. Als je dat doet, dan maakt de compiler genoeg ruimte vrij om ook die 'bar' binnen de Foo instantie op te slaan.
Het is die scope operator waar ik de nuance niet van snap, voor mij blijft dat iets als "ga binnen class Foo en doe daar dit" betekenen... in mijn hoofd is Foo::bar=4; equivalent met
C++:
1
2
3
4
struct Foo
{
    int bar=4;
};
wat wel mag...en als die dan toch geïnitaliseerd mag worden daar, dan snap ik niet waarom dat via de scope operator niet mag? En dan ook nog omdat het int is zoals daarstraks gezegd mag daar weer vanalles mee wat met objecten niet mag :D .
Juist. Maar inline is sowieso maar een hint.
Ja vandaar het stuk wat je nu net hebt weggelaten...
Als een compiler een functiedefinitie kent, kan hij zelf besluiten of hij inlinet. En met moderne compilers wordt code zelfs pas gegenereerd tijdens het linken, dus hij kan dan ook functiedefinities zien uit andere translation units en dan alsnog besluiten om te inlinen of niet.
En daarom dat ik me zorgen maak of het "per toeval" kan werken/niet werken...
Klopt. Het is ook niet de compiler die dit doet, maar de IDE. Die zal files met .cpp herkennen als C++ source files, en die dus ook door de compiler gooien. Kan nog steeds als je ze .koektrommel noemt, maar dat zul je dan even tegen je IDE moeten zeggen.
Aha, maar dat impliceert dat .h files geen "C++ source files" zijn... wat zijn dat dan, "C++ header files"? Nu merk je dat ik verwend ben door visual studio en geen idee heb wat die precies als opdracht geeft aan de compiler :D. Ik ging er maar van uit hij gewoon bij 1 file begon en dan daar de includes van af ging, en zo vertakte tot hij alle files had gehad, en naar de cpp files sprong op basis van de naam of zo.
Er crasht niets,
was figuurlijk bedoelt, in de zin dat de compiler ging opspelen.
maar je overtreedt de One Definition Rule omdat er meerdere definities van die functie bestaan binnen je programma. Je kan het oplossen door bla::func() alsnog als inline te definieren buiten de class :)
hehehe, maar dit gaat dus ook over die scope operator voor mij. En nu je zegt dat door inline te definieren (wat hij impliciet doet als je de body in de class body zet) het wel werkt kom ik tot de conclusie dat de scope operator toch wel degelijk hetzelfde is als iets binnen de class zetten, buiten dat het dan niet meer impliciet inline is?
Stel je hebt foo.cpp, die include "foo.h" en "bar.h", maar foo.h en bar.h includen beide <string>, dan wordt <string> dus twee keer geinclude, maar toch staan ze niet na elkaar.
Juist, juist, sorry, ik begon in de war te raken, maar je hebt gelijk. Je kan in headers ook includes hebben en die kunnen een header die je zelf include ook nog eens includen en dan zitten ze wel in dezelfde translation unit en niet in dezelfde file. Ik snap.
Natuurlijk moet het niet. Als jij niet wilt dat jouw methoden werken op const objecten dan moet je dat niet doen.
Dat is wat ik wou weten, dat die functies ontoegankelijk werden :) .
Maar in de regel wil je het wel. Dit noemt men const-correctheid.
ja dat heb ik nog gelezen op die C++ faq meen ik ... maar ik twijfelde over hoe het nu juist zat dus bedankt voor mijn twijfels te verjagen :).
Een object is ook niet "per ongeluk" const, maar is dat met een reden.
Met "per ongeluk" bedoel ik als het indirect const wordt, door middel van een functie die const returned of zo, en niet door een programmeur die het keyword const bij de declaratie zet :) .
Als een functie een referentie naar een object wilt dat hij niet aan gaat passen, dan vraagt die functie dus om een const reference naar dat object. Dit is handig omdat iedereen die zelf een referentie naar dat const object heeft dan weer die functie aan kan roepen.
Heb je het nu over een functie die deel is van dat object? Ah nee dat moet niet noodzakelijk, je bedoelt zeker dat iedereen die een "const" versie van een object van dat type die functie kan gebruiken omdat die z'n parameter als const aanneemt en zodoende belooft er niks aan te veranderen.
Pff, die 7 bits zijn je probleem niet. Vraag eens de properties van een willekeurige file in Windows op. Je ziet daar een "actual size" en een "size on disk". Die size on disk is typisch de filegrootte gealigned op de eerstvolgende 4 kilobyte boundary. Dus ook al wil je 1 bit opslaan in een file, hij wordt alsnog 4 kilobyte.
Ja, ik weet dat de slack space nog meer verspilt, maar het gaat me meer erom dat ik nu in mijn bestand moet gaan bewaren hoe lang mijn bestand eigenlijk is; en of ik wel helemaal tot het einde moet lezen. Anders kan ik gewoon lezen tot end of file en weet ik dat 't gedaan is als 't gedaan is, nu moet ik die laatste byte nog mogelijk iets van wegsmijten, en dat gaat alleen als ik precies weet tot waar ik moet gaan...informatie die je normaal uit bestandssysteem kan halen, maar nu dus niet.
Const correctness heeft vrijwel geen invloed op optimalisaties. Het feit dat het object waarnaar gerefereerd wordt const is wil niet zeggen dat dat object niet aangepast kan worden na een aanroep van een functie waarvan je de interne werking niet kent.
Vanuit een stuk code waar dat object bekend als niet-const dan? Want als je het doorgeeft als const, dan blijft het toch const..., omdat je geen functies mag aanroepen die niet beloven (met const argumenten) het object niet aan te passen? Een beetje alsof "const" besmettelijk is :) , zoals de GPL }) .
En als je die interne werking wel kent dan kun je ook bepalen of dat object al dan niet aangepast wordt (wat alsnog lastig is wegens aliasing).
aliasing, zoals met references of pointers die identiek zijn dus...
De enige mogelijke optimalisatie is als je het object zelf als const definieert.
Het verbaasd me nog steeds dat er iets te optimaliseren valt omdat het const is. Je zou denken dat het niet uitmaakt of er naar geschreven wordt of niet vermits dat allemaal in ram gebeurt waar overal alles even snel gaat....(itt harde schijven dus).
Tja, je vragen worden wel erg basic. Het lijkt me handiger als je gewoon een goed boek door gaat nemen.
Ben je nu m'n boek aan't bashen? :D
Je zal wel gelijk hebben, m'n parate kennis over het stuk van de reference variabelen is belabberd. En ja ik heb 2 boeken dus ik zal die andere ook maar eens doorlezen. Het probleem is echter dat ik zoveel tijd om te lezen niet heb op't moment, en ondertussen toch al vanalles moet klaar krijgen.

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op dinsdag 18 augustus 2009 @ 01:35:
[...]

Het was waarschijnlijk een array van chars,
yep (nuja, uint8, omdat de library die we moesten gebruiken dat zo deed, maar was gewoon een andere naam voor een char natuurlijk).
en die waarde is idd 205, ofwel 0xcd, wat de VC++ code is voor "dit geheugen is niet geïnitialiseerd".
aha, weer iets bijgeleerd. Gek dat niemand me dat ooit eerder verteld heeft :D. Da's vrij nuttig.
Dat zie je voornamelijk in debug builds. Je hebt wel meer van die codes, zoals 0xdd (dacht ik) voor "dit geheugen is vrijgegeven". Soms zie wat slimmer bedachte codes als 0xdeadbeef of 0xbaadf00d :). Wij gebruiken op 't werk 0xbaddaf1d, die je tegenkomt als de decompressiecode van m'n collega David niet goed werkt :Y)
lol :D - geweldig

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
Wikipedia heeft toch echt wel op alles een letterlijk antwoord he :)


Maar ik bedoelde dus eigenlijk binnen een functie, niet in de parameterlijst, dat het bij parameters efficienter is dan alles kopiëren is een duidelijk voordeel, maar binnen een class zit je meer namen te maken voor 1 en hetzelfde ding. Leuk als shortcut maar verder nutteloos...

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
.oisyn schreef op dinsdag 18 augustus 2009 @ 02:05:
[...]

Juist wel. 'ptr' wijst naar een const char. De char mag je dus niet wijzigen. De pointer zelf wel. De const slaat dus op 'char', niet op 'ptr'
ja klopt... slaaptijd voor mij, duidelijk.

Acties:
  • 0 Henk 'm!

  • Rygir
  • Registratie: Mei 2004
  • Laatst online: 01-03 05:45
NC83 schreef op dinsdag 18 augustus 2009 @ 02:05:
Als je een object const maakt zijn alle velden in die instance constant en je kunt enkel const member functies uitvoeren van deze instance.
Ok, maar hoe zit dat met pointers naar objecten, die pointers zijn dan als zijnde een veld constant geworden, maar de objecten waar ze naar verwijzen vermoedelijk niet?

Acties:
  • 0 Henk 'm!

  • Creepy
  • Registratie: Juni 2001
  • Laatst online: 21:31

Creepy

Tactical Espionage Splatterer

Tip: we hebben een "edit" knop ;)
offtopic:
Nu kom je nogal spammerig over ;)

"I had a problem, I solved it with regular expressions. Now I have two problems". That's shows a lack of appreciation for regular expressions: "I know have _star_ problems" --Kevlin Henney


Acties:
  • 0 Henk 'm!

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

MLM

aka Zolo

Rygir schreef op dinsdag 18 augustus 2009 @ 02:37:
[...]

Daar zeg je zo iets... zou op een 64 bits processor de int niet 64 ipv 32 bit moeten zijn?
Niet per definitie. Dat is een keuze per compiler, zo kwam eerder al ter sprake dat GCC LP64 gebruikt en MSVS LLP64 in x64 mode. Maar het zou goed kunnen, de standaard geeft alleen aan dat een char "1 byte" is, en een short groter, of gelijk aan char (en dan voor alle andere integer typen).
In theorie zou je dus prima een 1624byte long kunnen hebben op een compiler, of een long long van 1 byte op een andere compiler :)

Maar je kan altijd zelf een type verzinnen at altijd X grootte heeft, dmv compiler-afhankelijke typedefs:
code:
1
2
3
4
5
6
7
8
9
#if defined(_MSC_VER)
//een LLP64 compiler
typedef long long mijn_type;
#elif defined(__GCC)
//een LP64 compiler
typedef long mijn_type;
#else
#error Oops, ik begrijp je compiler niet :)
#endif


Maar als je een type zoekt met de "native size" van de processor, kan je volgens mij met de standaard "size_t" (unsigned versie) en "offset_t" (signed versie) al een heel eind komen, volgens mij is het gegarandeerd dat "sizeof(size_t) == sizeof(void *)" voor deze 2 types

[ Voor 1% gewijzigd door MLM op 18-08-2009 08:46 . Reden: zinsbouw ]

-niks-


Acties:
  • 0 Henk 'm!

  • NC83
  • Registratie: Juni 2007
  • Laatst online: 21-08 21:44
MLM schreef op dinsdag 18 augustus 2009 @ 08:44:
[...]


Niet per definitie. Dat is een keuze per compiler, zo kwam eerder al ter sprake dat GCC LP64 gebruikt en MSVS LLP64 in x64 mode. Maar het zou goed kunnen, de standaard geeft alleen aan dat een char "1 byte" is, en een short groter, of gelijk aan char (en dan voor alle andere integer typen).
In theorie zou je dus prima een 1624byte long kunnen hebben op een compiler, of een long long van 1 byte op een andere compiler :)

Maar je kan altijd zelf een type verzinnen at altijd X grootte heeft, dmv compiler-afhankelijke typedefs:
code:
1
2
3
4
5
6
7
8
9
#if defined(_MSC_VER)
//een LLP64 compiler
typedef long long mijn_type;
#elif defined(__GCC)
//een LP64 compiler
typedef long mijn_type;
#else
#error Oops, ik begrijp je compiler niet :)
#endif


Maar als je een type zoekt met de "native size" van de processor, kan je volgens mij met de standaard "size_t" (unsigned versie) en "offset_t" (signed versie) al een heel eind komen, volgens mij is het gegarandeerd dat "sizeof(size_t) == sizeof(void *)" voor deze 2 types
Ik zou in dit geval geen #error gebruiken maar een #warning en een struct maken met 2 ints om een 64 bits int mee te bouwen.
Ala LARGE_INTEGER

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


Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22:02
.oisyn schreef op dinsdag 18 augustus 2009 @ 01:35:
Wij gebruiken op 't werk 0xbaddaf1d, die je tegenkomt als de decompressiecode van m'n collega David niet goed werkt
Nerds :P

Anyways, @TS: Je stelt meer vragen dan je kunt verwerken. Zet em eens een versnelling terug en denk iets langer na voordat je de volgende vraag stelt.

[ Voor 24% gewijzigd door farlane op 18-08-2009 13:02 ]

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!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
NC83 schreef op dinsdag 18 augustus 2009 @ 11:29:
[...]

Ik zou in dit geval geen #error gebruiken maar een #warning en een struct maken met 2 ints om een 64 bits int mee te bouwen.
Ala LARGE_INTEGER
Maar je weet dus niet zeker of een int 32 of 64 bits is. Een error is nog niet zo gek, dan kan degene die wil compilen daar gewoon voor zijn compiler een define voor een 64 bits int neerzetten.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:24

.oisyn

Moderator Devschuur®

Demotivational Speaker

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
47
48
49
50
51
#include <iostream>
#include <climits>

template<bool COND, class THEN, class ELSE> struct if_then_else
{
    typedef THEN type;
};

template<class THEN, class ELSE> struct if_then_else<false, THEN, ELSE>
{
    typedef ELSE type;
};

template<class S, class U> struct int_type_info
{
    typedef S signed_type;
    typedef U unsigned_type;
};

template<int N> struct indexed_int;
template<> struct indexed_int<0> : int_type_info<signed char, unsigned char> { };
template<> struct indexed_int<1> : int_type_info<signed short, unsigned short> { };
template<> struct indexed_int<2> : int_type_info<signed int, unsigned int> { };
template<> struct indexed_int<3> : int_type_info<signed long, unsigned long> { };
template<> struct indexed_int<4> : int_type_info<signed long long, unsigned long long> { };

template<size_t BITSIZE, int N> struct find_int_type
{
    typedef typename if_then_else
    <
        BITSIZE <= sizeof(typename indexed_int<N>::signed_type) * CHAR_BIT,
        indexed_int<N>,
        typename find_int_type<BITSIZE, N+1>::type
    >::type type;
};

template<size_t BITSIZE> struct find_int_type<BITSIZE, 5>
{
    typedef void type;
};

template<size_t BITSIZE> struct int_type : find_int_type<BITSIZE, 0>::type { };


int main()
{
    std::cout << typeid(int_type<8>::signed_type).name() << std::endl;
    std::cout << typeid(int_type<16>::signed_type).name() << std::endl;
    std::cout << typeid(int_type<32>::signed_type).name() << std::endl;
    std::cout << typeid(int_type<64>::signed_type).name() << std::endl;
}

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!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Grappige oplossing, ik blijf me altijd verbazen over alle template trucjes die je toe kunt passen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”

Pagina: 1