2017-01-18 15 views
6

Czytam na elizji kopiowania (i jak to powinno być zagwarantowane w C++ 17) i to mnie trochę zmieszało (nie jestem pewien, czy znam rzeczy, o których myślałem wcześniej). Więc tutaj jest minimalny przypadek testowy:Co dzieje się w tym oświadczeniu zwrotu?

std::string nameof(int param) 
{ 
    switch (param) 
    { 
    case 1: 
     return "1"; // A 
    case 2: 
     return "2" // B 
    } 
    return std::string(); // C 
} 

Tak jak ja to widzę, przypadków A i B przeprowadzić bezpośrednią budowę o wartości zwracanej więc skopiować elizja nie ma sensu tutaj, natomiast sprawa C nie może wykonać kopii elizja ponieważ istnieje wiele ścieżek powrotu. Czy te założenia są prawidłowe?

Również chciałbym wiedzieć, czy

  • istnieje lepszy sposób pisania wyżej (np mieć std::string retval; i zawsze wrócić, że jeden lub napisać Szafy A i B jak return string("1") etc)
  • zdarza się jakikolwiek ruch, na przykład "1" jest tymczasowy, ale zakładam, że jest on używany jako parametr dla konstruktora std::string
  • są obawy dotyczące optymalizacji, które zostały pominięte (np. Wierzę, że C może być napisane jako return{}, czy byłby to lepszy wybór?)
+0

Dlaczego sądzisz przypadek A różni się od przypadku C. A jest skutecznie 'std :: string ("1")' 'i C jest std :: string ("")' –

+0

@KerrekSB Nic –

+0

@EdHeal Wierzę, że przypadek C jest równoważny 'std :: string (" 1 ")' elision copy musi nastąpić, czy nie ma żadnej różnicy od bezpośredniego konstruowania do wartości zwracanej? A może wiele ścieżek zwrotnych miesza się z elizacją kopiowania? Tak czy inaczej, o to pytam, więc nie pytaj mnie –

Odpowiedz

3

Aby był przyjazny dla NRVO, powinieneś zawsze zwracać ten sam obiekt. Wartość obiektu może być inna, ale obiekt powinien być taki sam.

Jednak powyższa reguła powoduje, że program jest trudniejszy do odczytania, a często należy wybierać czytelność ponad niezauważalną poprawę wydajności. Ponieważ std::string zdefiniowano konstruktor ruchu, różnica pomiędzy przesuwaniem wskaźnika a długością, a nie robienie tego byłaby tak mała, że ​​nie widzę żadnego sposobu, aby zauważyć to w aplikacji.

Co do ostatniego pytania, return std::string() i return {} byłyby dokładnie takie same.

Występują również niepoprawne stwierdzenia w pytaniu. Na przykład "1" nie jest tymczasowy. To literał ciąg. Tymczasowy jest tworzony z tego dosłownego.

Ostatnia, ale nie mniej ważna, obowiązkowa kopia w języku C++ 17 nie ma tutaj zastosowania. Jest ona zarezerwowana dla przypadków jak

std::string x = "X"; 

który przed obowiązkowym wymogiem może generować kod, aby utworzyć tymczasowy std::string i zainicjować x z kopią (lub ruchu) konstruktora.

1

We wszystkich przypadkach kopia może, ale nie musi zostać usunięta. Rozważmy:

std::string j = nameof(whatever); 

To może być realizowane na dwa sposoby:

  1. Tylko jeden std::string obiekt zostanie kiedykolwiek skonstruowany, j. (Kopia jest usuwana.)

  2. Obiekt tymczasowy std::string zostaje skopiowany do j, a następnie tymczasowy jest niszczony. (Funkcja zwraca tymczasowy, który jest kopiowany.)

Powiązane problemy