2012-07-07 14 views
8

Powiel możliwe:
Is pass-by-value a reasonable default in C++11?Kiedy należy wybrać elizę kopiowania w odniesieniu do przekazywania argumentu przez odniesienie do const?

Czytam Want Speed? Pass by Value. Dave Abrahams o kopię elizji i RVO. I zastanawiam się, dlaczego potrzebujemy elizacji kopiowania?

Powiedziano mi zbyt wiele razy, że powinieneś przekazywać argumenty funkcji przez odwołanie do konstelacji, aby uniknąć kopiowania (prawie każda książka C++, którą przeczytałem, powiedziała mi o tym).

Załóżmy, że mamy dwie funkcje:

int f1(const string &s); 
int f2(string s); 

Jeżeli rzeczywisty argument jest rvalue, kopiowanie uniknie się w obu tych funkcjach. Ale jeśli rzeczywisty argument jest l-wartości, kopiowanie będzie unikane tylko w f1, a nie w f2. Dlaczego potrzebujemy tej funkcji?

Odpowiedz

10

Przesyłaj według wartości, jeśli mimo wszystko potrzebujesz kopii. Niezależnie od tego, czy wybierzesz podpis f1, czy podpis f2 zależy od zawartości tej funkcji. Na przykład, należy użyć const odniesienia w tym przypadku:

int f1(const string& s) { 
    return s.size(); 
} 

Ale przechodzą przez wartość w tym przypadku:

int f2(string s) { 
    sort(s.begin(), s.end()); 
    s.erase(unique(s.begin(), s.end()), s.end()); 
    return s.size(); 
} 

ponieważ alternatywą byłoby to:

int f2(const string& s) { 
    string temp(s); 
    sort(temp.begin(), temp.end()); 
    temp.erase(unique(temp.begin(), temp.end()), temp.end()); 
    return temp.size(); 
} 
+1

Jedna uwaga: ten ostatni przypadek często występuje w konstruktorach. Biorąc pod uwagę 'struct S {S (...): s (s) {} std :: string s; }; ', to lepiej użyć' std :: string s' zamiast '...' zamiast 'std :: string const & s', ponieważ i tak będzie kopia. –

+2

@MatthieuM: Ale pamiętaj, aby przenieść go do elementu, a nie go skopiować. tj. 'S (std :: string s): s (std :: move (s)) {}' –

1

RVO nie ma zastosowania do twojego przykładu, ponieważ zwracana wartość to int.

string f1(const string &s) { 
    string ret = s; // always makes a copy 
    ret += 'x'; 
    return ret; // makes a copy pre-C++11 if no RVO 
} 

Tally: 1-2 kopie w C++ 03, dokładnie 1 w C++ 11 Plus (jeśli elizja jest wyłączona) ruch, który może przerodzić się kopią jakiegoś innej klasy niż std::string.

string f2(string s) { // calling makes a copy if lvalue or no elision 
    s += 'x'; 
    return s; // makes a copy pre-C++11 if no RVO 
} 

Tally: 0-2 kopii w C++ 03 lub 0-1 w C++ 11.

Jak powiedzieli inni, przekazuj wartości, gdy chcesz manipulować obiektem jako czystą wartością, bez semantyki odniesienia.

const & jest znanym idiomem, ale jest trochę kłopotliwy pod względem semantyki języka. Używasz go, gdy nie chcesz w ogóle korzystać z odnośnika; & służy tylko do tego, aby const było sensowne w definicji parametru. Jeśli chcesz zmodyfikować parametr (ale tylko lokalnie), wtedy const tak naprawdę nie ma zastosowania, a takżerównież.

0

f2 Sygnały po podpisie, bez względu na to, co mi przekażesz, zajmie się moją własną kopią twojego obiektu. Przydatne, jeśli f2 zamierza zmodyfikować obiekt w sposób nieodwracalny (na przykład ukraść jego zasoby przez ruch) lub w niektórych scenariuszach współbieżności. Co prawda C++ 11 dodaje nowy poziom zamieszania do (już mylącego) systemu typu C++, ale gdy się nad tym zastanowić, ma to wiele sensu ...

Powiązane problemy