vector

In einem vector wird eine (fast) beliebige Menge von Elementen so gespeichert, daß der Zugriff über einen Index (im Bereich von 0 bis (Anzahl der Elemente-1)) effektiv möglich ist. Dies kann über den Operator [] erfolgen, sodaß die Verwendung einem üblichen (eindimensionalen) Feld sehr ähnlich ist.

Allerdings ist die Anzahl der in einem vector gespeicherten Elemente zur Laufzeit einstellbar.

Dabei muß man allerdings beachten, daß die Feldgröße nicht durch bloße Verwendung eines Index wächst, sondern nur durch eine Anfangsgröße beim Erzeugen, durch explizites Einfügen oder Verlängern gesetzt wird (im Gegensatz zu der in Felder beliebigen Typs mit variablen Grenzen vorgestellten Lösung).

Beim Zugriff auf einzelne Elemente mit dem Operator [] wird -ebenso wie bei gewohnten Feldern- keine Feldgrenzenüberprüfung durchgeführt. Alternativ kann man mit der Methode at( size_t index ) eine Referenz auf das Element an der Position index erhalten; dabei wird die Einhaltung der aktuellen Feldgrenzen geprüft und im Fehlerfall eine Ausnahme out_of_range geworfen (siehe Ausnahmen der Standardbibliothek).

Ein kleines Beispiel für die Verwendung von vector erzeugt ein Feld von int-Werten:

// Time-stamp: "23.12.02 15:50 vector1.cpp klaus@wachtler.de"
//
// Demonstriert die Grundfunktionlität von vector<class T>.
//
// Y:\>cl /GX /W0 vector1.cpp & vector1
// v[0] = 10
// v[1] = 11
// v[2] = 0
// v[3] = 0
// v[4] = 0
// v[5] = 12
// v[6] = 13
// Element an der Stelle 10 = 49
// (hat geklappt)
// Fehler in main() entdeckt:
// invalid vector<T> subscript
// Element an der Stelle 10 = -5
// (hat geklappt)

#include <iostream>
#include <vector>
#include <stdexcept>

using namespace std;

int main( int nargs, char **args )
{

  vector<int>  v( 5 );  // 5 Elemente als Anfangsgröße

  try
  {
    v.push_back( 12 );    // ein (sechstes) Element anhängen
    v.push_back( 13 );    // ein (siebtes) Element anhängen

    v[0] = 10;      // ein Element verwenden (ohne Feldgrenzenüberprüfung)
    v.at( 1 ) = 11; // ein Element verwenden (mit Feldgrenzenüberprüfung)

    // alle Elemente ausgeben:
    for( unsigned i=0; i<v.size(); i++ )
    {
      cout << "v[" << i << "] = " << v[i] << endl;
    }

    // (vermutlich) ungestraft hinter das Feldende fassen:
    cout << "Element an der Stelle 10 = " << v[10] << endl;
    cout << "(hat geklappt)" << endl;

    // Ebenfalls hinter das Feldende fassen; aber hier kommt eine Ausnahme:
    cout << "Element an der Stelle 10 = " << v.at( 10 ) << endl;
    cout << "(hat geklappt)" << endl;
  }
  catch( exception &fehler )
  {
    cerr << "Fehler in main() entdeckt:" << endl;
    cerr << fehler.what() << endl;
  }
  catch( ... )
  {
    cerr << "Unbekannter Fehler in main() entdeckt" << endl;
  }
  try
  {
    // Feld verlängern, dann kommt auch keine Ausnahme!
    // auf 11 Elemente (0..10) verlängern, neue Werte stehen auf -5:
    v.resize( 11, -5 );
    cout << "Element an der Stelle 10 = " << v.at( 10 ) << endl;
    cout << "(hat geklappt)" << endl;
  }
  catch( exception &fehler )
  {
    cerr << "Fehler in main() entdeckt:" << endl;
    cerr << fehler.what() << endl;
  }
  catch( ... )
  {
    cerr << "Unbekannter Fehler in main() entdeckt" << endl;
  }

}

Die Ausgabe dieses Programms ist:

v[0] = 10
v[1] = 11
v[2] = 0
v[3] = 0
v[4] = 0
v[5] = 12
v[6] = 13
Element an der Stelle 10 = 134529592
(hat geklappt)
Fehler in main() entdeckt:
vector [] access out of range
Element an der Stelle 10 = -5
(hat geklappt)

Ein weiteres Beispiel zeigt neben der Erzeugung des Vektorinhalts auch die üblichen Möglichkeiten, über die vorhandenen Elemente zu iterieren:

// Time-stamp: "30.10.04 10:52 vec.cpp klaus@wachtler.de"
//
// demonstriert std::vector
//
// 25.10.2004 kw   unter Linux entworfen und getestet, mit VC6 nicht
//                 kompilierbar
//
// 27.10.2004 kw   Mit VC6 (cl 12.00.8168) getestet unter Windows 2000
//                 Übersetzen: cl /EHsc vec.cpp
//
// 29.10.2004 kw   Getestet mit MS VC++ 7.1 (VCToolkit),
//                 cl-Version 13.10.3077 unter Windows 2000
//                 Übersetzen: cl /EHsc vec.cpp
//
//                 Außerdem mit devcpp (g++ 3.3.1 mingw) getestet
//                 unter Windows 2000.
//                 Übersetzen mit g++ -Wall vec.cpp -o vec.exe
//
//                 Nach wie vor unter Linux mit g++ 3.3.4 lauffähig
//                 (g++ -Wall vec.cpp -o vec)
//
// 30.10.2004 kw   demo_foreach_fo() eingefügt
//

#include <iostream>
#include <vector>
#include <stdexcept>
#include <algorithm>


// Gibt einen beschreibenden (text) und anschließend einen vector
// Element für Element aus:
template<typename T> void zeigevector( const char *text, std::vector<T> v )
{
  std::cout << "vector\n" << text << std::endl;
  for( size_t i=0; i<v.size(); i++ )
  {
    std::cout << "[" << i << "] = " << v[i] << std::endl;
  }
  std::cout << std::endl;
}

std::vector<int> demo_simple()
{
  size_t   i;

  // vector aus int-Werten:
  std::vector<int>   vint(5);  // Anfangslänge 5

  for( i=0; i<vint.size(); i++ )
  {
    vint[i] = i*i;
  }

  zeigevector( "vint anfangs", vint );

  try
  {
    // Das Element an der Stelle 5 ist unzulässig!
    // Mit [5] kann trotzdem zugegriffen werden (auch auf die Gefahr
    // hin, daß das Programm Unsinn macht):
    std::cout << "vint[5]    = " << vint[5] << std::endl;

    // Hier wird dagegen zwar ebenfalls versucht, auf ein unzulässiges
    // Element zuzugreifen; aber bei at() wird dies zur Laufzeit
    // erkannt und eine Ausnahme geworfen:
    std::cout << "vint.at(5) = " << vint.at(5) << std::endl;

  }
  catch( std::exception &Fehler )
  {
    std::cerr << "Fehler: <" << Fehler.what() << "> in demo_simple()\n";
  }
  catch( ... )
  {
    std::cerr << "unbekannter Fehler in demo_simple()\n";
  }

  try
  {
    // Wenn man ein Element anhängt, geht alles klar:
    vint.push_back( 99 ); // verlängert um ein Element
    std::cout << "vint[5]    = " << vint[5] << std::endl;
    std::cout << "vint.at(5) = " << vint.at(5) << std::endl;

  }
  catch( std::exception &Fehler )
  {
    std::cerr << "Fehler: <" << Fehler.what() << "> in demo_simple()\n";
  }
  catch( ... )
  {
    std::cerr << "unbekannter Fehler in demo_simple()\n";
  }

  // Den vector etwas verlängern:
  vint.resize( 10 );
  for( i=5; i<vint.size(); i++ )
  {
    vint[i] = i*i;
  }

  // neuen Inhalt ausgeben:
  zeigevector( "vint nach Verlängern", vint );

  return vint;
}

// zeigt alle Elemente, Zugriff mit []
void demo_index( std::vector<int>  vint )
{
  std::cout << "demo_index:" << std::endl;
  // normale Schleife über alle Elemente:
  size_t  i;
  for( i=0; i<vint.size(); i++ )
  {
    std::cout << "vint[" << i << "] = " << vint[i] << std::endl;
  }
  std::cout << std::endl;
}

// zeigt alle Elemente, Zugriff mit at()
void demo_at( std::vector<int>  vint )
{
  std::cout << "demo_at:" << std::endl;
  // normale Schleife über alle Elemente:
  size_t  i;
  for( i=0; i<vint.size(); i++ )
  {
    std::cout << "vint.at( " << i << " ) = " << vint.at( i ) << std::endl;
  }
  std::cout << std::endl;
}

// zeigt alle Elemente, Zugriff mit einem Iterator
void demo_iterator( std::vector<int>  vint )
{
  std::cout << "demo_iterator:" << std::endl;
  // Iteration über alle Elemente:
  std::vector<int>::iterator  i;
  for( i=vint.begin(); i!=vint.end(); i++ )
  {
    std::cout << "*i" << " = " << *i << std::endl;
  }
  std::cout << std::endl;
}

// zeigt alle Elemente, Zugriff mit for_each und einer Funktion
// gibaus():

void gibaus( int i )
{
  std::cout << "i" << " = " << i << std::endl;
}
void demo_foreach_fkt( std::vector<int>  vint )
{
  std::cout << "demo_foreach_fkt:" << std::endl;
  // Schleife aus <algorithm> über alle Elemente; was mit jedem Objekt
  // zu geschehen hat, wird von der Funktion gibaus() definiert:
  std::for_each( vint.begin(), vint.end(), gibaus );
  std::cout << std::endl;
}

// zeigt alle Elemente, Zugriff mit for_each und einem Funktionsobjekt
// der Klasse gib:

// Ein Objekt dieser Klasse kann erstens mit einer int als Parameter
// aufgerufen werden (und gibt dann das Element aus), und zweitens
// werden diese Aufrufe mitgezählt und die Anzahl kann mit
// getAnzahlAufrufe() abgefragt werden.
class gib
{
public:

  // Konstruktor
  gib()
    : anzahlAufrufe( 0 )
  {}

  // Mit diesem Operator kann ein Objekt o dieser Klasse wie eine
  // Funktion mit einem int-Parameter aufgerufen werden, z.B.:
  //    o( 5 );
  void operator()( const int &aktuellesObjekt )
  {
    std::cout << "aktuellesObjekt = "
              << aktuellesObjekt
              << std::endl;
    anzahlAufrufe++;
  }

  // liefert zurück, wieoft operator()( const int &aktuellesObjekt )
  // schon für das aktuelle Objekt (*this) aufgerufen wurde:
  int getAnzahlAufrufe()
  {
    return anzahlAufrufe;
  }

private:

  int   anzahlAufrufe;

}; // class gib...

void demo_foreach_fo( std::vector<int>  vint )
{
  std::cout << "demo_foreach_fo" << std::endl;

  // Schleife aus <algorithm> über alle Elemente.
  // Was mit jedem Objekt zu geschehen hat, wird von dem
  // Funktionsobjekt fo definiert:
  gib  fo; // Funktionsobjekt, das als fo( int ) verwendet werden kann
           // (also wie eine Funktion, durch den operator() in gib).
           // Die Anzahl der Aufrufe wird intern mitgezählt.

  // Wenn man den Rückgabewert von for_each() nicht verwendet, kann
  // man anschließend nicht mehr die Anzahl der in fo gespeicherten
  // Aufrufe feststellen, weil fo an for_each mit call by referene
  // übergeben wird, also eine Kopie angelegt wird. In dieser Kopie
  // werden dann die Aufrufe gezählt; der Zähler in fo bleibt auf 0
  // stehen. Glücklicherweise liefert for_each() aber seine Kopie
  // wieder als Rückgabewert zurück; daher die Zuweisung an fo:
  fo = std::for_each( vint.begin(), vint.end(), fo );

  std::cout << std::endl;

  // Wieviele Elemente wurden ausgegeben?
  std::cout << "Es wurden " << fo.getAnzahlAufrufe()
            << " Elemente ausgegeben." << std::endl;
}

int main( int nargs, char **args )
{
  std::vector<int>   v;
  v = demo_simple();

  demo_index( v );
  demo_at( v );
  demo_iterator( v );
  demo_foreach_fkt( v );
  demo_foreach_fo( v );

  return 0;
} // main( int nargs, char **args )

Dazu ein paar Anmerkungen. Die Iteration über alle Elemente erfolgt:

Die Ausgabe des Programms ist dementsprechend:

vector
vint anfangs
[0] = 0
[1] = 1
[2] = 4
[3] = 9
[4] = 16

vint[5]    = 0
Fehler: <vector [] access out of range> in demo_simple()
vint[5]    = 99
vint.at(5) = 99
vector
vint nach Verlängern
[0] = 0
[1] = 1
[2] = 4
[3] = 9
[4] = 16
[5] = 25
[6] = 36
[7] = 49
[8] = 64
[9] = 81

demo_index:
vint[0] = 0
vint[1] = 1
vint[2] = 4
vint[3] = 9
vint[4] = 16
vint[5] = 25
vint[6] = 36
vint[7] = 49
vint[8] = 64
vint[9] = 81

demo_at:
vint.at( 0 ) = 0
vint.at( 1 ) = 1
vint.at( 2 ) = 4
vint.at( 3 ) = 9
vint.at( 4 ) = 16
vint.at( 5 ) = 25
vint.at( 6 ) = 36
vint.at( 7 ) = 49
vint.at( 8 ) = 64
vint.at( 9 ) = 81

demo_iterator:
*i = 0
*i = 1
*i = 4
*i = 9
*i = 16
*i = 25
*i = 36
*i = 49
*i = 64
*i = 81

demo_foreach_fkt:
i = 0
i = 1
i = 4
i = 9
i = 16
i = 25
i = 36
i = 49
i = 64
i = 81

demo_foreach_fo
aktuellesObjekt = 0
aktuellesObjekt = 1
aktuellesObjekt = 4
aktuellesObjekt = 9
aktuellesObjekt = 16
aktuellesObjekt = 25
aktuellesObjekt = 36
aktuellesObjekt = 49
aktuellesObjekt = 64
aktuellesObjekt = 81

Es wurden 10 Elemente ausgegeben.

AnyWare@Wachtler.de