ODR: Konstanten und Inlinefunktionen im Header
-
Dies war eigentlich als Antwort auf Tomahawk's Frage gedacht. Der Thread wurde schon geschlossen. Das habe ich aber leider erst dann gemerkt, als ich die geschriebene Antwort abschicken wollte. Ich denke Tomahawks Frage war berechtigt und sein Beispiel mit Konstanten und inline-Funktionen hat mich dazu veranlasst, eine ODR-Falle zu erwähnen, welche nicht ganz uninteressant sein dürfte:
Tomahawk schrieb:
Wandelt der Compiler nachfolgende Definition von Konstanten automatisch in eine Zahl um, so dass ich in den Inline Functions mit den Konstanten (noch auskommentiert) statt den unlesbaren Hexzahlen arbeiten darf, ohne dass etwas langsamer wird?
Weil der Wert von solchen Konstanten feststeht und sie nicht zur Laufzeit geändert werden dürfen, ist es einem Compiler erlaubt, die Namen der Konstanten an Stellen, wo Rvalues erwartet werden, direkt durch die Werte zu ersetzen, ohne dafür extra eine Konstante im Speicher anzulegen. Erst wenn die Adresse eines solchen Objekts benutzt wird, muss der Compiler auch Speicher für die Konstante anlegen. Diesbezüglich muss man aber etwas aufpassen:
Irgendeine Header-Datei:
#ifndef SOME_HEADER_INCLUDED #define SOME_HEADER_INCLUDED #include <vector> const int dings = 31415; inline void bums(std::vector<int> & v) { v.push_back(dings); } #endif // SOME_HEADER_INCLUDEDHier gibt es eine Verletzung der ODR (one definition rule), falls diese Headerdatei in mehreren Übersetzungseinheiten eingebunden wird.
dingshat eine interne Bindung,bumsaber nicht. Die ODR erlaubt die Mehrfachdefinition von Funktionstemplates und Inline-Funktionen (höchstens eine pro ÜE aber insgesamt auch mehr als eine), verlangt aber, dass die Definition dieselbe ist, wobei sich auch alle verwendeten Bezeichner auf dieselbe Entität beziehen, falls mehr als nur ihr Wert verwendet wird. In diesem Beispiel biezieht sich aberdingsimmer auf ein anderes Objekt, da jede ÜE ihr eigenesdingsbekommt. Diepush_back-Funktion nimmt ihren Parameter als Referenz-auf-const entgegen, was eine Adresse erfordert. Das führt dazu, dass die Definitionen von bums über versch ÜEs nicht mehr dieselben sind --> Verletzung der ODR.Die Variation
inline void bums(std::vector<int> & v) { v.push_back(dings+0); }erzeugt stattdessen ein temporäres int-Objekt und übergibt die Adresse der push_back-Funktion. Hier wird die ODR nicht mehr verletzt.
Gruß,
SP
-
Sebastian Pizer schrieb:
Die
push_back-Funktion nimmt ihren Parameter als Referenz-auf-const entgegen, was eine Adresse erfordert.Da bin ich nicht so sicher.