Skip to main content
swissICT Booster  |  M&F Academy  |  M&F Events   |  +41 44 747 44 44  | 
4 Minuten Lesezeit (740 Worte)

Einfacheres C++ mit C++11/14

Im M&F Trainee-Programm hatten wir einen spannenden Workshop über Programmierung mit C++11/14. Unser Referent war Peter Sommerlad. Er ist "Director of the IFS Institute for Software" an der Hochschule für Technik in Rapperswil sowie im ISO C++ Komitee und ausserdem Co-Autor von mehreren Büchern.

In meiner Zusammenfassung werden Neuerungen von C++11/14 vorgestellt, sowie einige Hilfsmittel und sonstige Coding-Guidelines. 

 

CUTE

Ein Hilfsmittel (frei erhältlich) zum Testen von C++ Code und gut geeignet für Test-Driven Design bzw. Refactoring.

auto

Ähnlich wie 'var' für die .NET Welt wird auto genutzt, um den Deklarationstypen automatisch zu bestimmen. Beispielsweise statt int a = 1; kann man auto a = 1; schreiben, da der Typ schon automatisch durch die Initialisierung bestimmt wurde. Auch bei Funktionen (inkl. Templates) kann auto eingesetzt werden.

! Hierbei muss man zwischen C++11 und C++14 unterscheiden. Beide unterstützen auto, jedoch kann C++14 noch mehr damit anfangen, z.B. man kann so den Rückgabetypen einer Methode genauer definieren.

Falls man nicht nur den Typen abkürzen möchte, sondern auch Referenzen (z.B. int&) so sollte man decltype(auto) verwenden.

Universal Initializer

Um Variablen und Listen/Arrays einfach und schnell zu initialisieren, gibt es nun den universal initializer {} zum initialisieren von solchen. Beispiel: std::vector v{3,1,4,1,5,9,2,6};

() rounD Definition, Declaration -- {} Curly Construction, Creation

Algorithmen benutzen, statt selber schreiben

Es gibt viele Algorithmen in der Standardbibliothek, welche sehr optimiert sind und z.B. Out-of-Bounds-Fehler vermeiden. Anstatt for/while loops sollte man wenn möglich diese benutzen. Eine kleine Auswahl von Beispielen:

  • std::distance()
  • std::for_each()
  • std::accumulate()

Beispiele für Vektor v:

Einfache for-Schleife: for(auto const i:v){...}

Oder Iteratoren v.begin(), v.end() verwenden: for (auto it=begin(v); it!=end(v); ++it){...}

Lambda

Ab C++11 werden Lambda-expressions unterstützt, welche dazu dienen, Funktionen wie Variablen zu behandeln und diese einfach zu deklarieren. Beispiel: auto printHello=[] { cout "hello world" endl;};

Special case: Falls die Variable innerhalb einer Lambda-expression veränderbar sein sollte, so muss die Lambda-expr. als mutable gekennzeichnet werden.

Functors

Ein Funktor ist eine Klasse, welche den ()-Operator überschreibt:

struct donothingfunctor{
    void operator()()const{}
};

Predicates

Predicates sind spezielle Lambdas oder Funktionspointer, welche einen Boolean oder einen Boolean-konvertierbaren Typ (Funktor) zurückgeben.

Sie werden häufig bei Container-Algorithmen verwendet um die zu verwendenden Elemente zu definieren.

Predicate

auto odd=[](int i){ return i%2; };

(Smart) Pointers

Es sollten keine normalen Pointers (z.B. new T{}) mehr verwendet werden, welche man dann selber wieder aufräumen muss. Stattdessen gibt es verschiedene Alternativen:

  • nullptr null pointer
  • shared_ptr Pointer mit reference counting => bei 0 references wird er zerstört.
  • unique_ptr non-shared pointer.

Simpler Classes

Sommerlad's rule of zero

Write your classes in a way that you do not need to declare/define neither a destructor, nor a copy/move constructor or copy/move assignment operator

 

New Value Terminology (lvalue, rvalue)

5 Errortypen von Funktionen

Es gibt fünf Möglichkeiten Fehler in einer Funktion abzufangen:

  1. ignore the error and provide potentially undefined behavior
  2. return a standard result to cover the error
  3. return an error code or error value
  4. provide an error status as a side effect
  5. throw an exception

Implementierung von Arithmetic Types

Wenn möglich sollte man dies vermeiden. Wenn nicht vermeidbar, so sollte man wenn möglich die Boost-Bibliothek benutzen. Sie benötigt dafür folgende Operationen:

  • operator== z.B. wird mit boost::equality_comparable {...} implementieren
  • operator()
  • operator+= z.B. mit boost::addable {...} implementieren
  • operator*=

 

Templates

Templates dienen dazu, gewisse Funktionen/Abläufe für verschieden Typen anzubieten (z.B. Int und Double) ohne Code zu duplizieren. Dazu gibt es verschiedene Arten von Templates:

Function Template

Eine Funktion kann mit verschiedenen Typen gebraucht werden. Hier ein Beispiel mit der Implementation einer Minimums-Funktion:

template typename T>
const& min(T const& a, T const& b){
    return (a b? a : b ;
}

Variadic Template Function

Diese Template-Art wird gebraucht, falls die Anzahl Argumente für eine Template-Funktion variabel sein kann. Beispiel:

template typename...ARGS>
void variadic(ARGS...argsargs){
    println(std::cout,args...);
}

Klassen Template

Zusätzlich zu einzelnen Funktionen können ganze Klassen als Template definiert werden. Die Syntax hierzu ist sehr ähnlich zu den obigen Beispielen. Im Gegensatz zu einem Funktionstemplate müssen aber die Typen bei der Deklaration immer genau angeben werden (z.B. std::vector)

Beispiel einer Klassen-Template-Definition: template class Sack;

 

Patterns in C++

Viele Patterns sind schon in der Standard Library enthalten (z.B. Iteratoren). Ansonsten sollten Patterns immer dort verwendet werden, wo sie Sinn ergeben.

Das Singleton-Pattern sollte nicht mehr verwendet werden.

 

Fun Facts aka nice to know:

  • std::vector ist der wichtigste Container
  • Boost Libraries stellen viele nützliche Features zur Verfügung (siehe http://boost.org)

Mehr zum Thema erfahren Sie in der Präsentation von Peter Sommerlad

 

Zurück zum Blog...

 

0
Optimierung von SQL Queries, O/R Mapping und mehr
BU-Leiter Riccardo Gubser im Interview

Ähnliche Beiträge

 

Kommentare

Derzeit gibt es keine Kommentare. Schreibe den ersten Kommentar!
Mittwoch, 15. Mai 2024

Sicherheitscode (Captcha)