[C++]klassen werken appart van elkaar perfect, maar los niet

Pagina: 1
Acties:
  • 298 views sinds 30-01-2008
  • Reageer

  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Ik ben momenteel een programma aan het schrijven dat bestaat uit verschillende klassen in één broncodebestand. Ik gebruik als compiler & GDE Dev-Cpp onder WinXP. Eén van de klassen geeft een raar probleem. Wanneer ik de klasse alleen gebruik dan werkt hij perfect. Maar doe ik nog iets anders voordat ik die klasse gebruik dan geeft de debugger hij de volgende error:
An acces violation (Segmentation Fault) raised in your program.
Daarbij geeft hij iedere keer dat ik iets willekeurigs heb veranderd een ander regelnummer.
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
class fman{
public:
    string* filename;
private:
    int size;
    void add(string r){
        size++;
        string* b = new string[size];
        for(int i = 0; i < size-1; i++)
                b[i] = filename[i];
        delete []filename;// <--
        filename = b;
        if(r != "")
                filename[size-1] = r;
    }
public:
    fman(string DirSpec){
        size = 0;
        WIN32_FIND_DATA FindFileData;
        HANDLE hFind = INVALID_HANDLE_VALUE;
        if(DirSpec.size() < MAX_PATH){
            hFind = FindFirstFile(DirSpec.c_str(), &FindFileData);
            if(hFind == INVALID_HANDLE_VALUE){
              add("FILE_ERROR");
            }
            else{
                add(FindFileData.cFileName);
                while(FindNextFile(hFind,&FindFileData) != 0){
                    add(FindFileData.cFileName);
                }
            }
        }    
    }
    ~fman(){
        delete []filename;
    }
    int NumberOfFiles(){
        return size;
    }
};


Dit werkt wel:
C++:
1
2
3
4
5
6
7
int main(){
    fman b("C:\\WINDOWS\\*");
    cout << b.filename[0] << endl;
    string q;
    cin >> q;
    return 0;
}


Dit werkt niet:
C++:
1
2
3
4
5
6
7
int main(){
    string q;
    cin >> q;
    fman b("C:\\WINDOWS\\*");
    cout << b.filename[0] << endl;
    return 0;
}


Het bestand ziet er zo uit:
#include <windows.h>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

class fman{}; (bovenstaande)

class config{}; (andere klasse)

int main(){}

Wat doet fman? fman zoekt de gespecificeerde directory af naar bestanden zodra hij aangemaakt wordt. Dan voegt hij aan de filename array een exemplaar toe met het nieuw gevonden bestandsnaam. In de functie add werk ik met de heap. Dus daar zit waarschijnlijk de fout.

Wanneer ik de regel:
delete []filename;
weghaal, dan werkt de code wel goed, maar hij zou toch ook moeten werken met die regel er in? Waarom werkt het de ene keer wel en de andere keer niet met die regel ertussen?

Wat is er fout? Of waar moet ik naar zoeken?

[ Voor 10% gewijzigd door -DarkShadow- op 11-08-2004 21:03 ]

Specialist in:
Soldeerstations
Oscilloscoop


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Je gebruik filename in add() die niet geinitialiseerd is.

(die pointer kan dus alles zijn, blijkbaar gaat het soms goed omdat het naar 'goed' geheugen point, en soms niet omdat het naar geheugen buiten bereik van je programma point -> access violation)

[ Voor 64% gewijzigd door Zoijar op 11-08-2004 21:06 ]


  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Zoijar schreef op 11 augustus 2004 @ 21:04:
Je gebruik filename in add() die niet geinitialiseerd is.

(die pointer kan dus alles zijn, blijkbaar gaat het soms goed omdat het naar 'goed' geheugen point, en soms niet omdat het naar geheugen buiten bereik van je programma point -> access violation)
Maar waarom werkt het dan wel zonder "delete []filename;"? Ik snap er niks van.

Is got daar ook zo langzaam?

Specialist in:
Soldeerstations
Oscilloscoop


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

offtopic:
ja het gaat ineens heel traag.


Het gaat al fout op regel 10, maar daarna delete je een pointer die niet geinitialiseerd is. Je wist dus iets dat niet bestaat. Ik denk dat je hem eerst in je ctor op 0 moet zetten, en dan alleen dat kopie maken als hij geen 0 is. Zoiets. Je code is een beetje....vreemd ;)

  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Zoijar schreef op 11 augustus 2004 @ 21:19:
offtopic:
ja het gaat ineens heel traag.


Het gaat al fout op regel 10, maar daarna delete je een pointer die niet geinitialiseerd is. Je wist dus iets dat niet bestaat. Ik denk dat je hem eerst in je ctor op 0 moet zetten, en dan alleen dat kopie maken als hij geen 0 is. Zoiets. Je code is een beetje....vreemd ;)
DISCLAIMER: Na "Hello World" is dit mijn allereerste C++ progsel. Ik heb járen VB geprogrammeerd, maar .NET trekt mij niet zo.

Ik denk dat ik weet wat je bedoeld :P

Specialist in:
Soldeerstations
Oscilloscoop


  • _Squatt_
  • Registratie: Oktober 2000
  • Niet online
Waarom geen std::vector gebruiken?

--- edit[0]
Als je een std::vector gebruikt hoef je je namelijk niet bezig te houden met pointers.

Als voorbeeld, met een std::vector wordt je class:
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
#include <vector>

class fman { 
    // Het is netter om de data van je class private te houden, en met een
    // functie toegankelijk te maken (zie filename() onderaan). Op die manier
    // kun je de interne opslag van je data veranderen zonder dat je de code
    // die gebruik maakt van je klasse hoeft te veranderen.
    std::vector<std::string> m_filenames;
    
    // add() is een stuk simpeler geworden.
    void add( std::string r) {
        m_filenames.push_back( r);
    }

public: 
    fman( std::string DirSpec) { 
        // ctor blijft hetzelfde
    }
    
    // dtor hoeft niets te doen, na de dtor worden de dtor's van je member
    // variabelen aangeroepen, en de destructor van std::vector ruimt het
    // geheugen dat een std::vector gebruikt netjes op.
    ~fman() {} 
    
    // we hoeven geen aparte variabele meer bij te houden voor het aantal files.
    int NumberOfFiles() {
        return m_filenames.size(); 
    }
        
    std::string const &filename( unsigned idx) {
        return m_filenames[idx];
    }
};


--- edit[1]
.oisyn heeft hieronder echter ook een goed punt.

Het ligt er maar net aan waar je je mee bezig wilt houden. Als je wat meer wilt weten over geheugenmanagement -> zelf implementeren. Als je dat nu niet interessant vindt -> gewoon een std::vector gebruiken zodat je je kunt richten op iets anders zonder je druk te maken over pointers.

[ Voor 157% gewijzigd door _Squatt_ op 12-08-2004 02:38 ]

"He took a duck in the face at two hundred and fifty knots."


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Och, gezien z'n nog beperkte ervaring lijkt het me een goede les dat soort dingen zelf 'ns te implementeren, daar leer je alleen maar van :)

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.


  • -DarkShadow-
  • Registratie: December 2001
  • Niet online
Hartstikke bedankt. Ik zal me eens richten op vectors. Ik ben bezig met Thinking in C++ 2nd ed. van Bruce Eckel.

Specialist in:
Soldeerstations
Oscilloscoop


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
.oisyn schreef op 12 augustus 2004 @ 01:58:
Och, gezien z'n nog beperkte ervaring lijkt het me een goede les dat soort dingen zelf 'ns te implementeren, daar leer je alleen maar van :)
Als je leert fietsen begin je och ook niet met leren fietsen met je handen los van het stuur? Gebruik en leer eerst de makkelijke dingen. Die laatste complexe 5% komt ooit wel.

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


Verwijderd

MSalters schreef op 12 augustus 2004 @ 10:33:
[...]

Als je leert fietsen begin je och ook niet met leren fietsen met je handen los van het stuur? Gebruik en leer eerst de makkelijke dingen. Die laatste complexe 5% komt ooit wel.
Precies. Lekker STL gebruiken, dat verkleint de kans dat je programma's brak worden aanzienlijk, en maakt het programmeren leuker (omdat je niet elke keer de zoveelste lijst of verzameling of boom implementatie hoeft te klussen).

Zoals ik in een boek over OOP ooit gelezen heb:
Waarom zou je het wiel uitvinden als je het kan erven?
Niet helemaal van toepassing maar wel amusant :p

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

MSalters schreef op 12 augustus 2004 @ 10:33:
[...]

Als je leert fietsen begin je och ook niet met leren fietsen met je handen los van het stuur? Gebruik en leer eerst de makkelijke dingen. Die laatste complexe 5% komt ooit wel.
Het probleem is dat de meeste mensen leren fietsen en vervolgens 10 jaar later geen benul hebben wat ze moeten doen als hun ketting eraf loopt of ze een lekke band hebben :)

Professionele website nodig?


  • farlane
  • Registratie: Maart 2000
  • Laatst online: 22-05 16:53
MSalters schreef op 12 augustus 2004 @ 10:33:
Als je leert fietsen begin je och ook niet met leren fietsen met je handen los van het stuur? Gebruik en leer eerst de makkelijke dingen. Die laatste complexe 5% komt ooit wel.
Misschien is het wel handig om uit te zoeken waar het stuur zit, voordat je op de fiets stapt. :)

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.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

MSalters schreef op 12 augustus 2004 @ 10:33:
[...]

Als je leert fietsen begin je och ook niet met leren fietsen met je handen los van het stuur? Gebruik en leer eerst de makkelijke dingen. Die laatste complexe 5% komt ooit wel.
Complex? Vroeg of laat heb je die info mijn inziens gewoon nodig. De STL bevat nog altijd geen goede smartpointer voorziening (auto_ptr is natuurlijk maar beperkt bruikbaar), en dus zul je hier en daar met ruwe pointers moeten werken. Ok, het array voorbeeld is hier natuurlijk makkelijk te vervangen door een vector, maar imho kan er niet vroeg genoeg ingestampt worden dat je je variabelen, en zeker pointers, moet initialiseren. Ik vind de analogie van curry dan ook een stuk beter.

Bedenk dat hij niet leert programmeren, hij heeft naar eigen zeggen jaren VB gebruikt (ok, voor zover je dat programmeren kunt noemen :P). Aangezien VB geen pointers kent lijkt mij dat een logische stap om aan te leren :)

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.


Verwijderd

.oisyn schreef op 12 augustus 2004 @ 14:54:
[...]


Complex? Vroeg of laat heb je die info mijn inziens gewoon nodig. De STL bevat nog altijd geen goede smartpointer voorziening (auto_ptr is natuurlijk maar beperkt bruikbaar), en dus zul je hier en daar met ruwe pointers moeten werken.
Eigenlijk wordt het werken met ruwe pointers steeds meer afgeraden. (Staat nog een leuk stukje over in de laatste CUJ van Herb Sutter). shared_ptr gaat ook toegevoegd worden aan de C++ standaard, en is al een stuk beter bruikbaar.

  • The_Eternal
  • Registratie: Oktober 2001
  • Laatst online: 18-10-2025
Verwijderd schreef op 12 augustus 2004 @ 22:28:
[...]


Eigenlijk wordt het werken met ruwe pointers steeds meer afgeraden. (Staat nog een leuk stukje over in de laatste CUJ van Herb Sutter). shared_ptr gaat ook toegevoegd worden aan de C++ standaard, en is al een stuk beter bruikbaar.
ik denk dat je niet om pointers heen kan in de wat geavanceerdere c++ code. Als je het niet wilt gebruiken kan je het pointer specefieke gedeelte altijd encapsuleren in een aparte class of iets dergelijks. Maar pointers geeft juist een vrijheid in programmeren wat je bij heel veel andere talen niet hebt. Maar ik ben het er wel mee eens dat als je het overal gaat gebruiken je wel sneller een onduidelijke/ondoorzichtige code krijgt.

Uhm... ja


Verwijderd

Ik wou net te zeggen: pointers zijn toch iets waar je liever niet mee te maken hebt.

Jaaah, pointers zijn heeeeel erg fijn om 86 optimalisatiehacks uit te voeren in je code, ik weet het, pointers zijn goed & fijn & je moet ze maar goed leren gebruiken. Maar ik hou van abstractie en met pointers wil ik me liefst niet bezighouden als ik het even kan vermijden.

En als er een stukje code is waar pointers wel nuttig zouden worden (voor snelheid), dan schrijf ik dat net zo lief in assembler. Als we toch gaan optimaliseren.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Even heel kort door de bocht: als je geen pointers wil moet je C# of Java pakken.

* curry684 snapt het geneuzel niet. Pointers zijn een machtig wapen waarmee je op- en top krachtige code kan schrijven. Als je dat geneuzel niet wil, pak dan een taal die ze niet heeft en die het je per definitie bespaart, want bij C++ ontkom je er per definitie niet aan.

Professionele website nodig?


Verwijderd

curry684 schreef op 12 augustus 2004 @ 22:45:
Even heel kort door de bocht: als je geen pointers wil moet je C# of Java pakken.

* curry684 snapt het geneuzel niet. Pointers zijn een machtig wapen waarmee je op- en top krachtige code kan schrijven. Als je dat geneuzel niet wil, pak dan een taal die ze niet heeft en die het je per definitie bespaart, want bij C++ ontkom je er per definitie niet aan.
Daarom gebruik ik ook geen C++ :Y).

Maar ik kan natuurlijk geen gelegenheid voorbij laten gaan om mijn geloof te prediken :p.

  • The_Eternal
  • Registratie: Oktober 2001
  • Laatst online: 18-10-2025
curry684 schreef op 12 augustus 2004 @ 22:45:
Even heel kort door de bocht: als je geen pointers wil moet je C# of Java pakken.

* curry684 snapt het geneuzel niet. Pointers zijn een machtig wapen waarmee je op- en top krachtige code kan schrijven. Als je dat geneuzel niet wil, pak dan een taal die ze niet heeft en die het je per definitie bespaart, want bij C++ ontkom je er per definitie niet aan.
precies ;) pointers is een van de dingen die ik b.v. erg in java mis :).
En nee je hebt ze niet nodig om iets te kunnen maken, maar soms zijn we wel verdomd handig, in java is het standaard een reference behalve als je clone gebruikt, maar dat geld weer niet voor de String class etc. etc. etc, soms toch beetje onduidelijk wat ze er nou mee willen :P (maar nu dwaal ik af :P)

Uhm... ja


Verwijderd

De disucussie gaat eigenlijk iets dieper dan dat. Het is geen kwestie van pointers of geen pointers, maar over het gebruik van smart pointers.

Met smart pointers druk geef je bv een 'transfer of ownership semantics' aan. Een bron functie kan expliciet hiermee aangeven dat de 'ownership' naar de caller toe gaat.

Overigens zitter jullie er allemaal een beetje naast hierboven. In Java heb je juist alleen maar pointers. In C++ maak je juist onderscheid tussen value-types en pointers. Het enigste verschil mbt pointers in Java en C++ is, dat je in C++ met pointers kunt rekenen.

Kort samengevat gebruik je in C++ een pointer (ipv een value) als:

• Polymorphic container met verschillende objecten van een common base
• Index containers (om via verschillende sortering door een container te lopen)
• voor types die niet value-like zijn (netwerk connectie object etc)

Quote van Herb Sutter:

Avoid using bald pointers.

en

For containers: Store only values and smart pointers in containers

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op 12 augustus 2004 @ 23:32:
Quote van Herb Sutter:

Avoid using bald pointers.
Leuke quote, het gaat alleen voorbij aan wat de aanleiding vormde voor deze discussie. Namelijk niet het gebruik van ruwe pointers, maar het leren omgaan met ruwe pointers. Smartpointers zijn natuurlijk leuk, maar ze lossen niet alle pointer problemen op en je blijft te maken hebben met potentiele memleaks. Beter probeer je dus te begrijpen wat pointers zijn en hoe ze werken, eveneens voor smart pointers, zodat je weet wat voor type smartpointer je wanneer moet gebruiken, en dat je het probleem sneller kan spotten als het een keer fout gaat (en dat je ook begrijpt waarom het fout gaat).

[ Voor 4% gewijzigd door .oisyn op 13-08-2004 11: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.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23-05 18:13
Verwijderd schreef op 12 augustus 2004 @ 23:32:
De disucussie gaat eigenlijk iets dieper dan dat. Het is geen kwestie van pointers of geen pointers, maar over het gebruik van smart pointers.

Met smart pointers druk geef je bv een 'transfer of ownership semantics' aan. Een bron functie kan expliciet hiermee aangeven dat de 'ownership' naar de caller toe gaat.

Overigens zitter jullie er allemaal een beetje naast hierboven. In Java heb je juist alleen maar pointers. In C++ maak je juist onderscheid tussen value-types en pointers. Het enigste verschil mbt pointers in Java en C++ is, dat je in C++ met pointers kunt rekenen.
Ik vind het feit dat je in Java geen gedoe met 'ownership' hebt ook wel relevant. Daardoor valt de noodzaak voor smart pointers weg.
Kort samengevat gebruik je in C++ een pointer (ipv een value) als:
• Polymorphic container met verschillende objecten van een common base
Waarom dan geen reference?
• voor types die niet value-like zijn (netwerk connectie object etc)
Wederom: waarom dan geen reference?

Ik gebruik zelf in C++ pointers vooral wanneer ze ook de waarde null aan kunnen nemen en eigen voor alle dynamisch gealloceerde objecten. (En natuurlijk voor arrays, voor zover die gebruik worden.) Bij diverse low-level datastructuren zoals binary trees zijn pointers bijzonder handig. Bij gewone functies en klassen voldoen references meestal wel. Tenslotte is het wel noodzakelijk om pointers in containers te stoppen omdat daar geen references in kunnen.
Quote van Herb Sutter:
For containers: Store only values and smart pointers in containers
Jammer dat de enige (dacht ik?) gestandaardiseerde 'smart' pointer (std::auto_ptr) niet geschikt is voor gebruik in de gestandaardiseerde containers. Als je uitsluitend op de C++ standard library wilt bouwen (wat toch vaak voorkomt) dan is dit advies dus onbruikbaar.

[ Voor 3% gewijzigd door Soultaker op 13-08-2004 15:38 ]


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 23-05 18:13
curry684 schreef op 12 augustus 2004 @ 22:45:
Even heel kort door de bocht: als je geen pointers wil moet je C# of Java pakken.

* curry684 snapt het geneuzel niet. Pointers zijn een machtig wapen waarmee je op- en top krachtige code kan schrijven. Als je dat geneuzel niet wil, pak dan een taal die ze niet heeft en die het je per definitie bespaart, want bij C++ ontkom je er per definitie niet aan.
In C++ kun je ze nog een beetje ontwijken. Vooral in C code (en C++ code die een C API gebruikt) worden ze veel gebruikt. Neemt niet weg dat je hoe dan ook het verschil tussen een waarde, een reference en een pointer moet begrijpen.
The_Eternal schreef op 12 augustus 2004 @ 22:48:
precies ;) pointers is een van de dingen die ik b.v. erg in java mis :).
En nee je hebt ze niet nodig om iets te kunnen maken, maar soms zijn we wel verdomd handig, in java is het standaard een reference behalve als je clone gebruikt, maar dat geld weer niet voor de String class etc. etc. etc, soms toch beetje onduidelijk wat ze er nou mee willen :P (maar nu dwaal ik af :P)
Volgens mij heb je niet heel veel begrepen van hoe Java werkt (niet lullig bedoelt). Je hebt uitsluitend references naar objecten. Met clone() kun je kopiën maken en daarma voorkomen dat je object gewijzigd wordt door buitenstaanders; je hebt dan nog steeds een reference maar qua werking gaat het meer de kant op van een value type omdat je een lokale kopie gemaakt hebt.

De reden dat je Strings nooit hoeft te clonen is dat het toch al immutable types zijn; buitenstaanders kunnen bestaande Strings in principe niet wijzigen, dus gedragen ze zich ook al enigzins als value types. Andere immutable types hoef je dus ook nooit te clonen.

Hoe dan ook; of je nu werkt met mutable of immutable types, je hebt in Java altijd te maken met references (die meer overeenkomsten vertonen met C/C++ pointers dan met C++ references).

  • flowerp
  • Registratie: September 2003
  • Laatst online: 04-02 02:01
Soultaker schreef op 13 augustus 2004 @ 15:36:
Jammer dat de enige (dacht ik?) gestandaardiseerde 'smart' pointer (std::auto_ptr) niet geschikt is voor gebruik in de gestandaardiseerde containers. Als je uitsluitend op de C++ standard library wilt bouwen (wat toch vaak voorkomt) dan is dit advies dus onbruikbaar.
std:auto_ptr kun je inderdaad beter niet in een container gebruiker (destructive copy semanctics enz, beetje rot bij sorteren), maar... shared_ptr wordt toegevoegd aan de standaard library. Met shared_ptr hoef je eigenlijk nooit meer auto_ptr te gebruiken, plus dat shared_ptr dus wel in containers gebruikt kan worden. :)

It's shocking to find how many people do not believe they can learn, and how many more believe learning to be difficult.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-05 23:07

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoals ik al eerder zei, ook shared_ptr lost niet alle problemen op (je hebt bijv. een probleem met cyclic references; een klasse Node met shared_ptrs naar de parent en de kinderen geeft al potentiele memleaks)

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.

Pagina: 1