2011-10-02 10 views
11

Czy istnieje potrzeba wydajność -wise dla inline funkcje przekazać swoje argumenty za const odniesienia jakInline Argumenty funkcji Uboczny

foo(const T & a, const T &b) 

porównaniu z wartością

foo(T a, T b) 

jeśli Nie zmieniam wartości a i b w funkcji? Czy zmiana w C++ 11 zaleca cokolwiek konkretnego tutaj?

+2

Wartość jest wartością, a odniesienie jest odniesieniem.Przekazywanie odwołania const, gdy znaczenie zamiast podania wartości jest błędem, który może źle się ugryźć. Zobacz http://stackoverflow.com/questions/4705593/int-vs-const-int/4705871#4705871 – 6502

+0

@ 6502: Jest to świetny przykład przypadku, w którym użycie odwołania powoduje, że logika jest bardziej skomplikowana ('v.push_back (v [0]) 'jest legalne, ponieważ biblioteka standardowa musi zawierać tę dodatkową logikę). –

+0

@BenVoigt: Miło widzieć to żądanie zostało dodane do standardu. Gdzie to jest napisane? – 6502

Odpowiedz

11

Przekazywanie według wartości może tylko spowodować odwołanie konstruktora kopii, jeśli argument jest tymczasowy.

Przekazywanie typów pierwotnych przez odniesienie do stałych nie będzie miało żadnych kosztów, gdy funkcja jest wbudowana. Ale podanie złożonej wartości przez wartość nałoży potencjalnie kosztowne wywołanie konstruktora kopii. Więc wolę przekazywać przez odniesienie do stałych (jeśli aliasing nie jest problemem).

+0

Oprócz problemów z aliasingiem występują problemy z życiem. – 6502

+0

@ 6502: Z pewnością zwraca wartości. W przypadku parametrów mogą wystąpić problemy z czasem życia, ale są one bardzo rzadkie. I tak uważałbym je za podzbiór zagadnień aliasingowych. –

+0

@BenVoigt 'Przekazywanie typów pierwotnych przez odniesienie do stałych nie będzie miało żadnych kosztów, gdy funkcja jest włączona. Czy masz na myśli" nie przynosi korzyści pod względem kosztów "? Czy możesz potwierdzić, czy jest coś, co można uzyskać, przekazując 'const int &' lub 'const int', gdy funkcja jest wbudowana? – Antonio

1

Pomijanie przez referencję jest szybsze niż według wartości w zależności od typu danych.
Jednak dla funkcji inline treść funkcji (a więc wszystkie wartości referencyjne/przekazywane w wartościach) są dodawane do linii kodu, z której są one używane, tak więc technicznie nie ma żadnych zmiennych, tylko więcej linii kodu w tym samym obszarze .

odniesienia http://www.cprogramming.com/tutorial/lesson13.html

Jest też bardzo pomocny odpowiedź pod pytaniem should-i-take-arguments-to-inline-functions-by-reference-or-value

  • Przykład może być mylące, usunięty -
+1

To jest całkowicie spekulacja. – pmr

+1

Przekazywanie przez odniesienie jest szybsze niż przez wartość ** w zależności od typu **. Również kod korzystający z odwołania ma dodatkowe wymagania (dla poprawnej obsługi aliasingu) i może wymagać dodatkowego pośrednictwa, którego nie potrzebują natywne typy przekazywane przez wartość. – 6502

+0

Przepraszam, przechodzę przez wskaźnik zmieszany z wartością z jakiegoś dziwnego powodu, masz rację, że jest tylko szybszy dla niektórych typów danych. Zwracam także uwagę na http://stackoverflow.com/questions/722257/ponowne-argumenty-do -inline-functions-by-reference-lub-value, które wspiera mój punkt – Serdalis

4

teoretycznie te, bez odniesienia mogą być kopiowane w pamięć, ponieważ istnieje możliwość, że twoja funkcja inline może je modyfikować (nawet jeśli tak naprawdę nie jest).

W wielu przypadkach kompilator jest wystarczająco inteligentny, aby wybrać takie rzeczy, ale zależy to od ustawień kompilatora i optymalizacji. Także jeśli twoja funkcja wywoła jakiekolwiek niestanowiące członka funkcje w zmiennych klasowych, twój kompilator będzie musiał być wystarczająco inteligentny, by sprawdzić, czy też coś modyfikuje.

Używając odniesienia do stałej wartości można w zasadzie nadać jej dość wyraźne wskazanie.

EDYCJA: Wystarczy spojrzeć na kod maszynowy dla prostego test program skompilowany z GCC 4.6 w ddd. Wygenerowany kod wydawał się identyczny, więc wydaje się, że został zoptymalizowany. Wciąż jest to dobra praktyka dla innych kompilatorów i jeśli nic innego nie daje wyraźnego wskazania intencji kodu. Możliwe jest również, że istnieją bardziej złożone sytuacje, których kompilator nie może jednak zoptymalizować.

Również tam llvm online dissembler demo pokazuje identyczny bitcode. Jeśli wyłączysz optymalizację, jest ona nieco dłuższa bez odniesienia do stałej.
* 1964 bajtów - Brak stałych odniesień (i żadnych innych stałych w funkcjach/parametrach)
* 1960 bajtów - Po prostu nie ma odniesienia const, ale inne stałe.
* 1856 bajtów - z odwołaniami do stałych i stałych.

+1

Jeśli funkcja inline przechodzi a i b do innej funkcji może nie być możliwe zoptymalizowanie kopii. Na przykład, jeśli funkcja inline wywołuje funkcję nieinkreśloną 'bar (a)', kompilator musi skopiować, ponieważ pasek może zrobić 'if (& a == & special) ...', a oryginalny program wywołujący mógł przekazać 'special'. –

+0

Spróbuj ponownie, używając urządzenia innego niż POD. –

+0

Dla optymalizatora nie ma znaczenia, czy funkcja składowa jest zadeklarowana jako "const" czy nie.Const-correctness jest niewidoczny dla optymalizatora i jest czymś, co zostało zaprojektowane tylko po to, aby pomóc programistom (dając błędy kompilacji, jeśli naruszasz deklaracje const), a nie optymalizatorowi. – 6502