2011-11-19 10 views
13

Porównaj rodzajowe funkcje integracji:przekazaniem obiektu funktora wartością vs poprzez odniesienie (C++)

template <class F> double integrate(F integrand); 

z

template <class F> double integrate(F& integrand); 

lub

template <class F> double integrate(const F& integrand); 

Jakie są plusy i minusy każdego ? STL używa pierwszego podejścia (przekazać według wartości), czy to oznacza, że ​​jest najbardziej uniwersalny?

+0

STL zwykle stosuje pierwsze podejście, ponieważ wiele problemów powstaje podczas korzystania z pojemników z referencjami itp. –

+2

Tak samo, jak wszędzie indziej: w zależności od tego, czym jest "F", wersje te mogą być różne, od identycznych do bardzo różnych. Jeśli 'F' jest stateful, tylko środkowa wersja może być możliwa. –

+0

Zasadniczo stawiasz wymagania swoim użytkownikom niezależnie od wybranej formy. Jeśli pod względem wartości, wymagasz od nich funktora, który można skopiować bez utraty integralności. Jeśli przez odniesienie musisz wymagać, aby dali ci coś w życiu odpowiedniego dla każdego użytkownika, który go umieszcza. – Mordachai

Odpowiedz

19

Obiekty funkcyjne zwykle powinny być małe, więc nie sądzę, że przekazywanie ich wartościami będzie odczuwalnie zauważalne (porównaj to z pracą, jaką funkcja pełni w swoim ciele). Jeśli przeszedłeś przez wartość, możesz również zyskać na analizie kodu, ponieważ parametr value według wartości jest lokalny dla funkcji, a optymalizator może określić, kiedy i kiedy nie można pominąć obciążenia z elementu danych funktora.

Jeśli funktor jest bezpaństwowcem, podanie go jako argumentu nie wiąże się z żadnymi kosztami - bajt wypełnienia, który pobiera funktor, nie musi mieć żadnej konkretnej wartości (w Itanium Abi używanym przynajmniej przez GCC). Podczas korzystania z referencji zawsze musisz podać adres.

Ostatni (const T&) ma tę wadę, że w C++ 03 nie działa dla surowych funkcji, ponieważ w C++ 03 program jest źle sformułowany, jeśli spróbujesz zastosować const do typu funkcji (i jest przypadkiem SFINAE). Nowsze implementacje zamiast ignorować const po zastosowaniu na typy funkcji.

Drugi (T&) ma oczywistą wadę, że nie można przekazać tymczasowych funktorów.

Krótko mówiąc, ogólnie rzecz biorąc, przekazywałbym je według wartości, chyba że widzę wyraźną korzyść w konkretnych przypadkach.

3

biorąc pod uwagę kontekst, oczekuje się, F za „wymagalne obiekt” (coś jak wolnej funkcji lub klasy posiadającej operatora() zdefiniowaną)

Teraz, ponieważ wolna nazwa funkcji nie może być L- wartość, druga wersja nie nadaje się do tego. Trzeci zakłada, że ​​operator F :: operator() ma być stały (ale może nie być, jeśli wymaga zmiany stanu F) Pierwszy działa na "własnej kopii", ale wymaga, aby F było kopiowalne.

Żadna z tych trzech kategorii nie jest "uniwersalna", ale pierwsza z nich najprawdopodobniej działa w najczęstszych przypadkach.

5

STB używa pierwszego podejścia (przejść przez wartość)

Oczywiście, standardowe biblioteki przechodzą iteratorami i funktory przez wartość. Zakłada się (słusznie lub niesłusznie), że są tanie w kopiowaniu, a to oznacza, że ​​jeśli piszesz iterator lub funktor, który jest drogi do skopiowania, być może będziesz musiał znaleźć sposób na zoptymalizowanie tego później.

Ale to tylko w celach, dla których standardowe biblioteki używają funktorów - w większości są to predykaty, choć są też takie rzeczy jak std::transform. Jeśli integrujesz funkcję, która sugeruje jakieś biblioteki matematyczne, w takim przypadku prawdopodobnie bardziej prawdopodobne jest, że będziesz mieć do czynienia z funkcjami mającymi duży stan. Można na przykład mieć klasę reprezentującą wielomian n-tego rzędu, z współczynnikami n + 1 jako niestatycznymi elementami danych.

W takim przypadku odniesienie do wartości stałej może być lepsze. Podczas używania takiego funktora w standardowych algorytmach, takich jak transform, można zawinąć go w małą klasę, która wykonuje pośrednie wskazanie za pomocą wskaźnika, aby zapewnić, że pozostanie on tani do skopiowania.

Wykonywanie odniesienia bez wartości stałych może być denerwujące dla użytkowników, ponieważ zatrzymuje ich przechodzenie w tymczasach.

Powiązane problemy