Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

BurningWave

Alter Hase

  • »BurningWave« ist der Autor dieses Themas

Beiträge: 1 106

Wohnort: Filderstadt/Konstanz

Beruf: Student

  • Private Nachricht senden

1

15.02.2013, 18:24

Return Value Optimization

Hallo,

ich habe gerade einen Artikel gelesen, der mein C++-Weltbild schon etwas durcheinander gebracht hat:
http://cpp-next.com/archive/2009/08/want…-pass-by-value/

Hier ist eine Funktion aus einem Projekt, an dem ich gerade arbeite:

C-/C++-Quelltext

1
2
3
4
5
const std::vector<Robot * const> World::GetRobots() const
{
    std::lock_guard<std::mutex> lg(Mutex);
    return Robots;
}


Bezüglich des Artikels werfen sich mir ein paar Fragen auf:
1. Kann man wirklich annehmen, dass der Compiler RVO anwendet? In welchen Fällen macht es dann überhaupt noch Sinn, etwas per konstanter Referenz zu übergeben?
2. Müsste in meinem Beispiel die letzte Zeile return Robots oder return std::vector<Robot * const>(Robots); heißen oder ist das egal?
3. Funktioniert der Lock-Guard überhaupt oder wurde dessen Destruktor zum Zeitpunkt des Kopiervorgangs schon aufgerufen?
4. Gehe ich recht in der Annahme, dass es nicht funktioniert, eine lokale Kopie in der Funktion zu erzeugen und diese als rvalue-Referenz zurückzugeben, da auch rvalue-Referenzen auf lokale Objekte ungültig werden?

Vielen Dank für eure Antworten.

Helmut

5x Contest-Sieger

Beiträge: 692

Wohnort: Bielefeld

  • Private Nachricht senden

2

15.02.2013, 18:50

RVO funktioniert nur für lokale Variablen, die zurückgegeben werden. Darauf verlassen, dass der Compiler diese Optimierung anwendet, kann man sich nicht. Und ja, auch Rvalue Referenzen werden ungültig, wenn sie auf Variablen im Stack zeigen, dessen Funktion schon returnt hat. Die restlichen Fragen kann ich nicht sicher beantworten...
Sei stets geduldig gegenüber Leuten, die nicht mit dir übereinstimmen. Sie haben ein Recht auf ihren Standpunkt - trotz ihrer lächerlichen Meinung. (F. Hollaender)

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

3

16.02.2013, 03:53

1. Kann man wirklich annehmen, dass der Compiler RVO anwendet?

Bei einem einigermaßen aktuellen Compiler schon, MSVC 2012 machts z.B.:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>


struct blub
{
  blub()
  {
    std::cout << "blub c'tor\n";
  }

  blub(const blub&)
  {
    std::cout << "blub copy c'tor\n";
  }

  ~blub()
  {
    std::cout << "blub d'tor\n";
  }
};


class Fabulous
{
  blub b;
public:

  blub f()
  {
    return b;
  }

};


int main()
{
  Fabulous f;
  auto x = f.f();

  return 0;
}

Output:

Quellcode

1
2
3
4
blub c'tor
blub copy c'tor
blub d'tor
blub d'tor


In welchen Fällen macht es dann überhaupt noch Sinn, etwas per konstanter Referenz zu übergeben?

RVO bzw. Copy Elision im Allgemeinen (RVO ist nur eine konkrete Art von Optimierung, die auf Copy Elision basiert) funktioniert halt nur in ganz bestimmten Fällen. Bei dem, woran du da denkst, kann der Compiler lediglich unnötige Kopien temporärer Objekte auslassen (unter der zusätzlichen Bedingung, dass diese nicht schon an eine Referenz gebunden wurden). Spätestens sobald du ein benanntes Objekt übergeben würdest, müsste dieses wieder kopiert werden. Auch darf man nicht vergessen, dass es sich hier um Optimierungen handelt, die der Standard lediglich erlaubt, nicht aber verlangt. Du kannst von einem modernen Compiler erwarten, dass er es tut, du kannst dich aber im Allgemeinen nicht darauf verlassen.

2. Müsste in meinem Beispiel die letzte Zeile return Robots oder return std::vector<Robot * const>(Robots); heißen oder ist das egal?

Sofern Robots vom Typ std::vector<Robot * const> ist, dürfte das effektiv keinen Unterschied machen, da der Compiler die temporäre Kopie einfach eliden wird... ;)

3. Funktioniert der Lock-Guard überhaupt oder wurde dessen Destruktor zum Zeitpunkt des Kopiervorgangs schon aufgerufen?

Afaik funktioniert das.

4. Gehe ich recht in der Annahme, dass es nicht funktioniert, eine lokale Kopie in der Funktion zu erzeugen und diese als rvalue-Referenz zurückzugeben, da auch rvalue-Referenzen auf lokale Objekte ungültig werden?

Rein Prinzipiell sind rvalue References erstmal einfach nur normale Referenzen wie lvalue References auch. Die Unterschiede kommen bei Dingen wie Overload Resolution und Template Argument Deduction zum tragen. Durch rvalue-References wird es jedenfalls ganz sicher nicht auf magische Weise plötzlich weniger falsch, Referenzen auf lokale Objekte zu returnen...

Werbeanzeige