2011-10-20 18 views
11

Jeśli chcesz umieścić definicje funkcji w plikach nagłówkowych, wydaje się, istnieją trzy różne rozwiązania:wprowadzenie definicji funkcji w plikach nagłówkowych

  1. zaznaczyć funkcję inline
  2. zaznaczyć funkcję jak static
  3. umieścić funkcję w anonimowym obszarze nazw

(Do niedawna nie byłem nawet świadomy # 1). Jakie są różnice między tymi rozwiązaniami, a kiedy ja Czy wolałbym który? Jestem w świecie tylko nagłówkowym, więc naprawdę potrzebuję definicji w plikach nagłówkowych.

+8

Zapomniałeś: zamień je w szablony funkcji. To zazwyczaj wolę. – sbi

+1

nie używaj statycznego, który prowadzi do wielu różnych kopii i szaleństwa. –

+2

Rozwiązanie "Jedna kopia w każdym anonimowym obszarze" prowadzi do tego samego szaleństwa. – MSalters

Odpowiedz

11

static i nienazwane wersje przestrzeni nazw są takie same: każda jednostka tłumaczenia będzie zawierała własną wersję funkcji, co oznacza, że ​​z uwagi na funkcję statyczną f, wskaźnik &f będzie różny w każdej jednostce tłumaczeniowej, a program będzie zawierał literę N różne wersje f (więcej kodu w pliku binarnym).

To nie właściwe podejście do zapewnienia się funkcji w nagłówku, będzie dostarczać N różne (dokładnie równe) funkcji. Jeżeli funkcja zawiera static mieszkańców to nie będzie N różne static zmienne lokalne ...

EDIT: Aby to bardziej wyraźne: jeśli to, co chcesz jest dostarczenie definicji funkcji w nagłówku bez łamiąc regułę jednej definicji, właściwym podejściem jest wykonanie funkcji inline.

+0

Więc 'inline' to właściwe podejście? Byłoby miło, gdybyś to jasno sprecyzował. – fredoverflow

+0

Moje zrozumienie tego było podobne i napisałem to samo, co odpowiedź, ale potem ją usunąłem, ponieważ byłem trochę utknięty z Q: "Jak funkcja zdefiniowana w nagłówku jako inline, powoduje ominięcie ODR?', Myślałem, że sekcja $ 3.2/5' odnosi się do tego, ale nie byłam pewna. Jest to prawdopodobnie więcej szczegółów niż szukano w Q, ale możesz to wyjaśnić. –

+0

@Als: 3.2/3 * Każdy program zawiera dokładnie jedną definicję każdej nieinrzędnej funkcji lub obiektu, który jest używany w tym programie; diagnostyka nie jest wymagana. [...] Funkcja inline powinna być zdefiniowana w każdej jednostce tłumaczeniowej, w której jest używana. * (Sformułowanie z C++ 03, ale to samo można znaleźć w C++ 11, gdzie * użyte * to * ODR-użyte *) –

0

static funkcje (równoważne anonimowej przestrzeni nazw) otrzymują różne kopie dla każdej JT. Jeśli funkcja jest ponownie wprowadzana, jest to zasadniczo identyczna (niektóre kompilatory mogą mieć różnice na poziomie zespołu), ale jeśli nie, to będą miały różne statyczne dane dla każdej JT. Funkcje śródliniowe są złożone - to znaczy, że mają tylko jedną kopię danych statycznych dla każdej JT.

+1

@TonyK: Chociaż zgadzam się z sugestią, że nie używam skrótów i używania pełnych notatek, zdecydowanie nie zgadzam się z "OP oczywiście nie jest ekspertem". OP jest jednym z niewielu ekspertów w SO, który naprawdę rozumie C++ rdzeń. –

+2

Cóż, postanowiłem usunąć mój komentarz, ale jest za późno ... Pozwólcie, że powtórzę to tutaj: Używanie skrótu, takiego jak TU, zakłada poziom doświadczenia w czytniku, który sprawia, że ​​twoje wyjaśnienia są zbędne. (Chyba że, jak się wydaje, twój czytelnik to FredOverflow.) A BTW, to znaczy Jednostka tłumacząca. – TonyK

4

O ile wiem, tylko inline i funkcje szablonu można zdefiniować w plikach nagłówkowych.

static funkcje są nieaktualne, a zamiast nich należy zastosować funkcje zdefiniowane w nienazwanej przestrzeni nazw (patrz 7.3.1.1 p2). Po zdefiniowaniu funkcji w nienazwanej przestrzeni nazw w nagłówku, każdy kod źródłowy zawierający ten nagłówek (bezpośrednio lub pośrednio) będzie miał unikalną definicję (patrz 7.3.1.1 p1). Dlatego funkcje nie powinny być zdefiniowane w nienazwanej przestrzeni nazw w plikach nagłówkowych (tylko w plikach źródłowych).

Podane standardy pochodzą ze standardu C++ 03.

EDIT:

Następny przykład pokazuje, dlaczego funkcje i zmienne nie powinny być zdefiniowane w przestrzeni nazw bezimiennego w nagłówkach:

ops.hpp zawiera:

#ifndef OPS_HPP 
#define OPS_HPP 
namespace 
{ 
int a; 
} 
#endif 

DK1 .hpp zawiera:

#ifndef DK1_HPP 
#define DK1_HPP 
void setValue(); 
void printValue(); 
#endif 

dk1.cpp zawiera:

#include "dk1.hpp" 
#include "ops.hpp" 
#include <iostream> 

void setValue() 
{ 
    a=5; 
} 
void printValue() 
{ 
    std::cout<<a<<std::endl; 
} 

dk.CPP zawiera:

#include "dk1.hpp" 
#include "ops.hpp" 
#include <iostream> 

int main() 
{ 
    // set and print a 
    setValue(); 
    printValue(); 

    // set and print it again 
    a = 22; 
    std::cout<<a<<std::endl; 

    // print it again 
    printValue(); 
} 

kompilacji tak:

g++ -ansi -pedantic -Wall -Wextra dk.cpp dk1.cpp 

i wyjście:

5 
22 
5 

ops zmienna a jest różna dla pliku źródłowego dk1.cpp i dk.cpp

+0

Nie ma nic złego jako takiego, mając anonimowe przestrzenie nazw z definicjami funkcji w nagłówkach - to nie jest naruszenie funkcji "statycznych" ODR – Flexo

+0

nigdy nie były przestarzałe, tylko obiekty 'statyczne' (przed C++ 11). –

+1

@awoodland: Z punktu widzenia kompilatora nie ma nic nie w porządku, ale najprawdopodobniej jest on z punktu widzenia programu. Funkcja ** ** w nagłówku jest w rzeczywistości ** wieloma ** funkcjami w różnych jednostkach tłumaczeniowych, generuje dodatkowy kod (większy plik binarny, gorsza wydajność pamięci podręcznej instrukcji) i jeśli funkcja zawiera * lokalne statyczne * zmienne, każda jednostka tłumaczeniowa odwoła się do własnej wersji. Kompilator zrobi to i będzie szczęśliwy. Ale ktokolwiek będzie musiał to debugować w przyszłości, nie będzie tak szczęśliwy. –

Powiązane problemy