auto&& mit Tücken

Dieses auto ist cool schrieb ich mal. Und das stimmt auch weiter. Trotzdem muss ich jetzt ergänzen:

Es ist cool, wenn man es richtig einsetzt und nicht mit Vollgas gegen die Wand fährt.


Ich musste mich jetzt wieder mal sehr über mich selbst ärgern.
Ein seltsames Problem trat auf, wobei unter Linux eine spezielle Dateisuche mit boost::filesystem fehlschlug, die unter Windows brav arbeitete.

… oder sagen wir mal, unter Windows im Debug-Modus brav arbeitete …

Nach einer quälenden Suche an den falschen Stellen, landete ich irgendwann bei der Zeile:

1auto&& dirname = dirpath.filename().string();

dirname beinhaltete nach der Zeile nur noch defekte Datenblöcke.

Hmm … Habe ich nicht mal gesagt, dass auto&& die beste Möglichkeit ist, den Rückgabewert einer Funktion generisch anzunehmen?

Ja, das stimmt auch, aber nur wenn der Typ auch stabil bleibt, und das ist in dem Beispiel nicht der Fall.

Denn dirpath.filename() erzeugt ein neues temporäres Objekt und .string() gibt eine konstante String-Referenz auf einen seiner Member zurück.

auto&& macht dann genau das, was es gut kann, nämlich den std::string const & entgegenzunehmen.

Doch nach dieser Zeile wird das temporäre Objekt von dirpath.filename() zerstört und die konstante String-Referenz zeigt jetzt auf freigegebenen ungültigen Speicher.

Fazit

Gefahr erkannt, Gefahr gebannt

würde ich sagen … aber es ärgert mich, dass mir das nicht gleich aufgefallen ist. auto&& ist nur gut, wenn es einen Rückgabewerte der ersten Ebene direkt erhält, wie z.B.:
auto&& subtext = text.substr(...);

Die Lösung des Code-Problems ist aber einfach:

1auto dirname = dirpath.filename().string();

Hier wird auto in einen einfachen std::string aufgelöst, und der bewirkt eine Kopie des Elements aus dem temporären Objektes.
Diese Kopie überlebt dann auch regulär die Zerstörung der temporären Instanz und kann gefahrlos weiter eingestetzt werden.

Alternative hätte man aber natürlich auch:

1auto&& dirpath_filename = dirpath.filename();
2auto&& dirname = dirpath_filename.string();

schreiben können. … doch das sieht etwas seltsam aus.