Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Zweidimensionales vector-Objekt als Referenz übergeben

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 < [ 2 ]
000
29.11.2015, 00:26 Uhr
Yadgar



Hi(gh)!

Einer Funktion readTGA, die ein unkomprimiertes 24-bit-TGA von Festplatte einlesen und aus den eingelesenen Bilddaten pixel-Objekte erzeugen soll (siehe mein letztes Posting) übergebe ich eine Referenz auf ein zweidimensionales vector-Objekt:


C++:
bool readTGA(<vector<vector<pixel> > &img, string filename)



Da die Dimensionsgrößen dieses vector-Objektes erst nach dem Einlesen des TGA-Headers feststehen, stelle ich vor dem Einlesen der eigentlichen Bilddaten mittels folgender Schleife den Speicherplatz bereit:


C++:
  for(h = 0; h < height; h++)
    img[h].resize(width);    



Dies führt merkwürdigerweise zu einer Fehlermeldung:

[Error] no matching function for call to 'pixel::pixel()'

obwohl doch hier noch gar keine pixel-Objekte initialisiert werden sollen!

In einem anderen Programm hatte ich die gleiche Konstruktion mit dem Typ int verwendet, da funktionierte es...

Was mache ich falsch?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
29.11.2015, 16:23 Uhr
ao

(Operator)


Doch, da werden pixel-Objekte erzeugt. resize legt Speicherplatz an und füllt ihn mit default-konstruierten Objekten.

Damit das geht, musst du für die Pixel-Klasse einen Default-Konstruktor (d.h. einen parameterlosen) bereitstellen.

Dass das mit int geht, liegt daran, dass die eingebauten Datentypen Default-Konstruktoren haben.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
03.12.2015, 00:42 Uhr
Yadgar




Zitat von ao:
Doch, da werden pixel-Objekte erzeugt. resize legt Speicherplatz an und füllt ihn mit default-konstruierten Objekten.

Damit das geht, musst du für die Pixel-Klasse einen Default-Konstruktor (d.h. einen parameterlosen) bereitstellen.

Dass das mit int geht, liegt daran, dass die eingebauten Datentypen Default-Konstruktoren haben.


Jetzt habe ich einen solchen Default-Konstruktor dazugenommen:


C++:
class pixel
{
  public:
    pixel(); // Standard-Konstruktor
    pixel (int, int, int); // Allgemeiner Konstruktor
    ~pixel(); // Destruktor
    void set_all(int, int, int);
    void set_red(int);
    void set_red(unsigned char);
    void set_green(int);
    void set_green(unsigned char);
    void set_blue(int);
    void set_blue(unsigned char);
    void get_all(rgb&);
    unsigned char get_red();
    unsigned char get_green();
    unsigned char get_blue();
    void invert();
  private:
    unsigned char r;
    unsigned char g;
    unsigned char b;
};

pixel::pixel()
{}



bekomme aber jetzt stattdessen zur Laufzeit einen Speicherzugriffsfehler, und zwar befindet sich die Fehlerquelle in der Funktion loadTGA (ehemals readTGA), der das zweidimensionale vector-Objekt übergeben wird, genauer gesagt, hier:


C++:
  for (c=0; c<height; c++)
  {  
    cout << "Hallo!" << endl;
    img[c].resize(width);
  }



Die Schleife gibt einmal "Hallo!" aus und bricht dann mit besagtem Speicherzugriffsfehler ab - warum?

Ich wüsste auch nicht, wie das das Problem anders lösen könnte als mit einer Übergabe per Referenz - die beiden Dimensionsgrößen sind ja erst nach Lesen des TGA-Headers überhaupt bekannt!

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog

Dieser Post wurde am 03.12.2015 um 00:43 Uhr von Yadgar editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
03.12.2015, 07:37 Uhr
ao

(Operator)


Weil du vor der Schleife noch img.resize (height) machen musst, damit es img[0] ... img[height-1] überhaupt gibt?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
03.12.2015, 15:48 Uhr
Yadgar



Hi(gh)!


Zitat von ao:
Weil du vor der Schleife noch img.resize (height) machen musst, damit es img[0] ... img[height-1] überhaupt gibt?


Habe ich jetzt gemacht, der Speicherzugriffsfehler verschwand - aber dafür habe ich gleich den nächsten Laufzeitfehler:

terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid

...und zwar *nach* dem Aufruf von loadTGA, obwohl main dort (erst einmal) zu Ende ist:


C++:
    loadTGA(image, source);
    cout << "Hallo!" << endl;  // wird NICHT angezeigt, stattdessen Laufzeitfehler!
    // invert();
    // saveTGA(img, destination);
      }
    }
  }
  return 0;
}



Ich bin ratlos...

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
03.12.2015, 22:02 Uhr
Hans
Library Walker
(Operator)


Hi,

wie wäre es, wenn Du erst mal nur Speicherplatz für den TGA-Header zur Verfügung stellst, und erst einmal nur diesen aus der Datei liest. Anschliessend kannst Du die Pixelobjekte beim auswerten des Headers gleich mit den richtigen Werten initialisieren. Dann sollten die bisherigen Fehler erst gar nicht mehr auftreten können... - vermute ich jetzt jedenfalls mal so.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 03.12.2015 um 22:22 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
03.12.2015, 23:26 Uhr
Yadgar



Hi(gh)!


Zitat von Hans:
Hi,

wie wäre es, wenn Du erst mal nur Speicherplatz für den TGA-Header zur Verfügung stellst, und erst einmal nur diesen aus der Datei liest. Anschliessend kannst Du die Pixelobjekte beim auswerten des Headers gleich mit den richtigen Werten initialisieren. Dann sollten die bisherigen Fehler erst gar nicht mehr auftreten können... - vermute ich jetzt jedenfalls mal so.



Wie soll ich denn die Pixelobjekte im vector initialisieren, wenn ich nur den Header, aber noch nicht den eigentlichen Datenteil eingelesen habe?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog

Dieser Post wurde am 03.12.2015 um 23:26 Uhr von Yadgar editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
04.12.2015, 01:06 Uhr
Hans
Library Walker
(Operator)


Hi,

ich stelle fest, dass ich mich wohl unklar ausgedrückt habe Also noch mal:
Ich stelle mir das so vor, dass Du als erstes die 18 Byte des Dateikopfs liesst. Da steht doch drin, wie hoch und wie Breit das zu ladende Bild ist und wieviele Bytes pro Pixel belegt werden. Damit kannst Du ausrechnen, wieviel Speicher Du für das Bild benötigst. Und erst wenn Du diese Information hast, reservierst Du den Speicher, den Du für Deine Pixelobjekte brauchst. Dann erst liest Du die Pixeldaten aus der Datei aus und füllst Deine Pixelobjekte damit. Ich hoffe, damit ist jetzt klarer, wie ich das meine.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
04.12.2015, 15:02 Uhr
ao

(Operator)



Zitat von Yadgar:
Habe ich jetzt gemacht, der Speicherzugriffsfehler verschwand - aber dafür habe ich gleich den nächsten Laufzeitfehler:

terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct null not valid

...und zwar *nach* dem Aufruf von loadTGA, obwohl main dort (erst einmal) zu Ende ist:


Das letzte Mal, als du diese Meldung hattest, hast du gesagt, es lag an einem vergessenen return.

Wenn du nicht weißt, was Fehlermeldungen bedeuten, dann googel sie einfach mal. Manchmal bekommt man dabei wertvolle Hinweise. Hier scheint es so zu sein, dass du irgendeine std::string-Variable mit NULL konstruierst, was man nicht tun sollte. Sind vielleicht die Übergabeparameter, die loadTGA bekommt, Schrott?

Ansonsten mach mal um den loadTGA-Aufruf ein try-catch-Konstrukt, kompilier das so, dass Exceptions möglich sind (falls das nicht schon so ist) und führ das Ganze im Debugger aus.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
009
04.12.2015, 23:01 Uhr
Yadgar



Hi(gh)!


Zitat von ao:

Das letzte Mal, als du diese Meldung hattest, hast du gesagt, es lag an einem vergessenen return.



*anKopfklatsch*

Ich bin noch mal den Code durchgegangen - natürlich, das war es!

Jetzt läuft das Programm formell einwandfrei durch - und tut doch nicht, was es soll!

Denn: der zweidimensionale vector wird per Referenz übergeben und in der Funktion dann dimensioniert, danach folgt eine Auslese-Schleife, in der die einzelnen Bytes einem vorher definierten Einzelobjekt vom Typ pixel (p) zugeordnet werden - nach jedem dritten Byte (die Reihenfolge bei TGA ist blau, grün, rot) wird dann p per push_back dem vector hinzugefügt.

Solange ich nur auf p mit dessen get-Methoden zugreife, sehe ich die korrekten Farbwerte (die Bilddatei ist testhalber winzig klein, nur 2 x 2 Pixel) - sobald ich aber auf das entsprechende pixel-Tripel im vector zugreifen will, werden mir nur Nullen angezeigt!

Hier der Code:


C++:
  unsigned int imgsize = width*height;
  unsigned int c; // counter

  img.resize(height);
  
  for (c=0; c<height; c++)
  {  
    img[c].resize(width);
  }
  
  c=0;
  pixel p;
  
  Source.seekg(18, ios_base::beg); // file pointer is set to 18th byte
  while (Source.get(ch) && Source.tellg() <= 18+imgsize*3 )
  {  
    switch (c%3)
    {
      case 0:
    p.set_blue((unsigned char)ch);
    // cout << (int)(unsigned char)p.get_blue() << endl;
        break;
      case 1:
    p.set_green((unsigned char)ch);
    // cout << (int)(unsigned char)p.get_green() << endl;
    break;
      case 2:
    p.set_red((unsigned char)ch);
    // cout << (int)(unsigned char)p.get_red() << endl;
    img[(c/3)/width].push_back(p);
        cout << "Row " << (c/3)/width << ", col " << (c/3)%width << endl;
    cout << "Red:   " << (int)img[(c/3)/width].at((c/3)%width).get_red() << endl;
    cout << "Green: " << (int)img[(c/3)/width].at((c/3)%width).get_green() << endl;
    cout << "Blue:  " << (int)img[(c/3)/width].at((c/3)%width).get_blue() << endl;
    }
    
    c++;
  }



width, height und daher auch imgsize haben korrekte Werte (andernfalls würden mir entweder mehr als vier Farbtripel oder womöglich sogar wieder ein Laufzeitfehler angezeigt).

Zur Erinnerung noch mal die Klasse mit den relevanten Methoden:


C++:
class pixel
{
  public:
    pixel(); // Standard-Konstruktor
    pixel (int, int, int); // Allgemeiner Konstruktor
    ~pixel(); // Destruktor
    void set_all(int, int, int);
    void set_red(int);
    void set_red(unsigned char);
    void set_green(int);
    void set_green(unsigned char);
    void set_blue(int);
    void set_blue(unsigned char);
    void get_all(rgb&);
    unsigned char get_red();
    unsigned char get_green();
    unsigned char get_blue();
    void invert();
  private:
    unsigned char r;
    unsigned char g;
    unsigned char b;
};




C++:
void pixel::set_red(int red)
{
  r = (unsigned char)red;
}

void pixel::set_red(unsigned char red)
{
  r = red;
}

void pixel::set_green(int green)
{
  g = (unsigned char)green;
}

void pixel::set_green(unsigned char green)
{
  g = green;
}

void pixel::set_blue(int blue)
{
  b = (unsigned char)blue;
}

void pixel::set_blue(unsigned char blue)
{
  b = blue;
}

unsigned char pixel::get_red()
{
  return r;
}

unsigned char pixel::get_green()
{
  return g;
}

unsigned char pixel::get_blue()
{
  return b;
}



Die set-Methoden sind überladen, es gibt sie jeweils auch für int-Parameter (damit ich bei späteren Anwendungen auch int-Literale übergeben kann), aber daran liegt es nicht, ich habe sie in diesem Fall hier in beiden Versionen getestet, es kamen so oder so am Ende immer nur Nullen heraus. Ebensowenig hat das Problem mit dem Rückgabeformat der get-Methoden zu tun, eine zeitweilige Umstellung auf int führte ebenfalls zu keiner Veränderung.

Woran liegt es aber dann?

Bis bald im Khyberspace!

Yadgar
--
Flagmaker - ein Programmier-Blog
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 < [ 2 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: