Inhalt:
Diese Seite ist entstanden für die Teilnehmer unseres Bilverarbeitungs-Projektes, das als regelmäßige KOGS-Lehrveranstaltung Mittwoch nachmittags stattfindet.
C++ Literatur / Dokumentation
Die Links, die ich am häufigsten zum Nachschlagen verwende, sind:
- die SGI STL Referenz (gute und übersichtliche Referenz, allerdings beschränkt auf die STL, d.h. vector, string usw, aber keine iostreams)
- die Dinkumware C++ Library Reference (ausführlich, umfaßt STL und IO Klassen)
- die Referenzdoku von www.cplusplus.com, die wiederum nicht die STL, aber die iostream library und die aus C stammenden Standardmodule cstdio, cstdlib, cstring, ctime und cmath enthält
Außerdem verwende ich ggf. Ullis Software Engineering Hotlist, eine umfangreiche, aber knapp kommentierte Linkliste. Um Eure Java-Vorkenntnisse zu nutzen, wäre es hilfreich, wenn ich mehr Seiten wie Cay Horstmann's C++ vs. Java-Seite finden würde (gerade den Pointer-Teil finde ich nicht 100%ig zustimmungswürdig, und er behandelt nicht die auch in C++ vorkommenden Referenzen). Es gibt sogar ein Addison-Wesley Buch 'C++ For Java Programmers', dessen Inhaltsangabe vielversprechend scheint. Auch Ross Paterson's 'Object Oriented Programming in C++' Slides könnten hilfreich sein.
Ich selber kenne nur wenig C++ Bücher, daher erstmal nur zwei Tips:
- Es gibt das Buch 'Thinking in C++' von Bruce Eckel kostenlos zum Download im Netz (hier ist auch eine längere Erklärung zu finden, warum sich das für den Autor/Verlag lohnt - auf jeden Fall kann das Buch nicht so schlecht sein, sonst würde es sich ja nicht mehr verkaufen lassen).
- Jan hat auch das Buch 'Intensivkurs C++' von Andrew König empfohlen (buch.de, Amazon).
Weitere Tipps
Ich kann einige gute Links zum Thema API-Design empfehlen; das ist ein sehr wichtiges Thema! Meiner Meinung nach sollte man immer so programmieren, als ob man eine API für jemanden anders schreibt, d.h. z.B. folgende Punkte zu beachten:
- Gute Namen für Funktionen und Argumente sind IMO das A und O. (Ich kann das nicht oft genug betonen!) Wer nach einigen Wochen oder Monaten seinen Quelltext des letzten Semesters wieder öffnet und sich erstmal wieder einlesen muß, weiß wovon ich rede. Je mehr Code Ihr schreibt, je mehr verschiedene Programme und -Teile, desto öfter werdet Ihr leiden, wenn Ihr Euch an Euren Code gewöhnen müßt, weil er nicht auf den ersten Blick klar gegliedert ist.
- Bekämpft Redundanz so früh wie möglich! D.h., Code sollte möglichst nie kopiert werden, sondern in Unterfunktionen ausgelagert werden. Dave Astels schrieb einmal folgenden (relativ kurzen) Post u.a. zu diesem Thema: Why Your Code Sucks
- Eine gute Gliederung der Funktionalität in sinnvolle Teile ist ebenfalls sehr wichtig. Anfänger neigen dazu, zu wenig Unterfunktionen zu verwenden, oder zu komplizierte Signaturen. Eine Funktion sollte möglichst wenig Argumente haben, 0-2 sind meist optimal, wenn man mehr braucht, sollte man die API überdenken - z.B. Argumente in structs oder Klassen gruppieren, ggf. die Funktion dann sogar zu einer Methode machen, die dann oft gar keine Argumente mehr braucht.
- Niemals "mal eben" Code schreiben - man benutzt den Code immer länger als man denkt, kopiert ihn in andere Projekte, gibt ihn an andere Leute, etc. Es lohnt sich immer, vorher über die o.g. Punkte nachzudenken.
- Unit-Tests sind kein Spielzeug der Softwaretechnik-Community, sondern sehr hilfreiche Werkzeuge! Ich verwende sie insbesondere, wenn ich kleine Hilfsfunktionen schreibe, die ich potentiell wiederverwenden will. Auch testgetriebene Entwicklung ist wirklich hilfreich, z.B. wenn ich eine Polygon-Klasse schreibe und mir vorher überlege, was sie leisten soll. Dann kann ich mit den Unit-Tests anfangen und die Klasse entsprechend anpassen, bis die Tests funktionieren. Der Vorteil ist, daß man sich auf die getesteten Teile seines Programms verlassen kann und damit viel Zeit bei der Fehlersuche spart. (Idealerweise muß man auch immer weniger Fehler suchen, aber es ist noch kein Meister vom Himmel gefallen.)
Ein sehr guter Artikel zum Thema API-Design orientiert sich an der von mir sehr geschätzten Qt-Bibliothek, ist aber für jeden verständlich zu lesen, auch wenn man noch nie von Qt gehört hat: Designing Qt-Style C++ APIs.
Kryptische Fehlermeldungen
Gerade bei generischer Programmierung mit Templates (z.B. mit der VIGRA) hat man oft ellenlange Fehlermeldungen, die nur schwer zu lesen sind. Beispiel:
./cppmap.hxx: In member function 'vigra::SafeFilterIterator<__ gnu_cxx::__normal_iterator<boost::shared_ptr<GeoMap::Face>*, s td::vector<boost::shared_ptr<GeoMap::Face>, std::allocator<boo st::shared_ptr<GeoMap::Face> > > >, NotNull<boost::shared_ptr< GeoMap::Face> > > GeoMap::finiteFacesBegin()': ./cppmap.hxx:239: error: conversion from 'vigra::FilterIterato r<__gnu_cxx::__normal_iterator<boost::shared_ptr<GeoMap::Face> *, std::vector<boost::shared_ptr<GeoMap::Face>, std::allocator <boost::shared_ptr<GeoMap::Face> > > >, NotNull<boost::shared_ ptr<GeoMap::Face> > >' to non-scalar type 'vigra::SafeFilterIt erator<__gnu_cxx::__normal_iterator<boost::shared_ptr<GeoMap:: Face>*, std::vector<boost::shared_ptr<GeoMap::Face>, std::allo cator<boost::shared_ptr<GeoMap::Face> > > >, NotNull<boost::sh ared_ptr<GeoMap::Face> > >' requested
Das Tool STLFilt filtert solche Fehlermeldungen (und schlimmere) und formatiert sie, um sie lesbarer zu machen, hier z.B.:
./cppmap.hxx: In member function 'vigra::SafeFilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::iterator
, NotNull<boost::shared_ptr<GeoMap::Face>>
> GeoMap::finiteFacesBegin()':
./cppmap.hxx:239: error: conversion from 'vigra::FilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::iterator
, NotNull<boost::shared_ptr<GeoMap::Face> >
>' to non-scalar type 'vigra::SafeFilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::iterator
, NotNull<boost::shared_ptr<GeoMap::Face> >
>' requested
./cppmap.hxx: In member function 'vigra::SafeFilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::const_iterator
, NotNull<boost::shared_ptr<GeoMap::Face>>
> GeoMap::finiteFacesBegin() const':
./cppmap.hxx:250: error: conversion from 'vigra::FilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::const_iterator
, NotNull<boost::shared_ptr<GeoMap::Face> >
>' to non-scalar type 'vigra::SafeFilterIterator<
vector<boost::shared_ptr<GeoMap::Face> >::const_iterator
, NotNull<boost::shared_ptr<GeoMap::Face> >
>' requested
Software
Auf der Homepage von Ullrich Köthe findet Ihr die VIGRA zum Download, bzw. die VIGRA Dokumentation.
Für Windows soll Dev-C++ eine gute (und kostenlose) IDE sein; auf der Download-Seite findet Ihr jeweils eine Version mit und eine ohne den GNU Compiler. Außerdem ist Microsoft sehr daran interessiert, daß Ihr Euch an deren Produkte gewöhnt (und später viel Geld dafür bezahlt), daher bekommt Ihr im Rahmen des MSDN Academic Alliance Programms in Haus D gegen Vorlage Eures Studi-Ausweises auch aktuelle Versionen des MS Developer Studio.
Übersetzen mit der VIGRA
Mit vigra-config --cppflags --impex-lib werden die nötigen Flags für den Compiler/Preprocessor und den Linker ausgegeben, sodaß z.B. die Beispiel-Programme der VIGRA mit Kommandos wie
g++ `vigra-config --cppflags --impex-lib` invert.cxx -o invert
übersetzt werden können. Ohne die zusätzlichen Parameter würde der Compiler die VIGRA-Headerdateien bzw. die Laufzeitbibliothek (libvigraimpex, wg. imp-ort/ex-port) nicht finden.
| Datei: Makefile | (1655 Bytes; Thu, 24. Jan. 2008) | |
Anbei findet Ihr ein Beispiel-Makefile, das Ihr an Eure persönlichen Bedürfnisse anpassen könnt.
Wenn Ihr die VIGRA auf Eurem persönlichen Rechner installiert, ist es also wichtig, daß vigra-config im Pfad ist. Außerdem muß ggf. die libvigraimpex im Library-Path sein, damit man anschließend die Programme starten kann:
export PATH=<VIGRA-Prefix>/bin:$PATH export LD_LIBRARY_PATH=<VIGRA-Prefix>/lib:$LD_LIBRARY_PATH
Hierbei bezeichnet "VIGRA-Prefix" den Pfad, in den man die VIGRA installiert hat (mit make install). Dieses ist standardmäßig das Verzeichnis, in dem auch die Quellen liegen, man kann es aber ggf. bei configure angeben:
./configure --prefix=/usr/local
(/usr/local/ ist z.B. ein nur vom Superuser beschreibbarer Standardpfad unter Linux für selbstkompilierte Programme, der oft schon in PATH und LD_LIBRARY_PATH enthalten ist.)
Kompilieren in (X)Emacs
Folgende Zeilen in der ~/.emacs sind sehr praktisch, damit man mit [F9] einen Kompilationsvorgang anstossen kann, aber vor allem, damit man mit [F10] zu den Codestellen springen kann, die der Kompiler anmeckert:
; den Kompilationsvorgang nicht riesig gross darstellen: (set-variable 'compilation-window-height 9) ; TERM=dumb setzen, damit GCC keinen farbigen Output erzeugt: ; (verwirrt nur / macht alles unlesbar, Emacs macht selber farbig) (set-variable 'compile-command "TERM=dumb make -k") ; nicht jedesmal nachfragen: (set-variable 'compilation-read-command nil) ; Tastenbelegungen: (global-set-key '[f9] 'compile) (global-set-key '[f10] 'next-error)
VIGRA selbst "auschecken"
Wenn Ihr die VIGRA selber übersetzen wollt, um sie auf Eurem Rechner zu installieren, könnt Ihr entweder die neueste veröffentlichte Version von der VIGRA-Homepage herunterladen oder die tagesaktuelle Version wie folgt mit Mercurial besorgen:
hg clone http://www.informatik.uni-hamburg.de/~meine/hg/vigra/
Ich hatte ein kurzes Tutorial (auf Englisch und für VIGRA/interactive2) angefangen, in dem ein paar Basis-Befehle für die Python-Bindings erläutert werden, allerdings sind seit Version 1.7.0 bessere Python-Bindings, in denen Bilder als NumPy Arrays repräsentiert werden, schon Teil der offiziellen VIGRA (leider mit einem anderen Funktionsumfang).
Header-Files
Hier will ich einige Headerdateien zur Verfügung stellen, die für Euch von Interesse sein könnten; zuallererst will ich quaternion.hxx anbieten, eine Quaternionen-Template-Klasse. Die ist noch ziemlich frisch, also nehme ich gerne Kommentare/Verbesserungsvorschläge entgegen.
VigraCaster
Ihr könnt den VigraCaster wie folgt "auschecken" (d.h. mein Mercurial Repository clonen):
hg clone ~meine/volrend/VigraCaster/
Für den VigraCaster braucht Ihr außer der VIGRA auch VigraQt. Anschließend könnt Ihr das Programm wie folgt kompilieren und starten (UNIX):
cd volrend/VigraCaster/ qmake make && ./qtgui
Wenn Ihr Eure ausgecheckte Version aktualisieren wollt, könnt Ihr dazu "hg pull" verwenden, Kurzform:
cd volrend/VigraCaster/ hg pull
Es ist auch möglich, von einem externen Rechner transparent über SSH auf mein Repository zuzugreifen:
hg clone ssh://meine@rzdspc10/~meine/volrend/VigraCaster/
Ich habe weitere Seiten mit einer Beschreibung der Koordinatensysteme und mit einer TODO-Liste für den VigraCaster online gestellt (beides in englisch).