2011-10-20 17 views
11

Si usted quiere poner las definiciones de funciones en los archivos de cabecera, parece que hay tres soluciones diferentes:poniendo definiciones de funciones en los archivos de cabecera

  1. marcan la función como inline
  2. marcan la función como static
  3. poner la función en un espacio de nombre anónimo

(Hasta hace poco, ni siquiera era consciente de # 1.) Entonces, ¿cuáles son las diferencias de estas soluciones, y cuando sh ¿Preferiría cuál? Estoy en el mundo de solo encabezado, así que realmente necesito las definiciones en los archivos de encabezado.

+8

Olvidó: conviértalas en plantillas de funciones. Eso es lo que generalmente prefiero. – sbi

+1

no use estática que genere muchas copias y locura. –

+2

La solución de "una copia en cada espacio de nombre anónimo" lleva a la misma locura. – MSalters

Respuesta

11

El static y las versiones de espacios de nombres sin nombre terminan siendo las mismas: cada Unidad de Traducción contendrá su propia versión de la función, y eso significa que dada una función estática f, el puntero &f será diferente en cada unidad de traducción, y el programa contendrá N diferentes versiones de f (más código en el binario).

Esto es no el enfoque correcto para proporcionar una función en un encabezado, que proporcionará N funciones diferentes (exactamente iguales). Si la función contiene static lugareños, entonces habrá N diferentes static variables locales ...

EDIT: Para hacer esto más explícito: si lo que quiere es proporcionar la definición de una función en un encabezado sin rompiendo la regla de una sola definición, el enfoque correcto es hacer que la función inline.

+0

Entonces 'en línea' es el enfoque correcto? Sería bueno si lo hicieras explícito. – fredoverflow

+0

Mi comprensión sobre esto fue similar y publiqué lo mismo que una respuesta, pero luego la borré, ya que estaba un poco atrapado con la Q, '¿Cómo hacer que una función definida en el encabezado sea en línea, hace que eludir el ODR?', Pensé' Sección $ 3.2/5' aborda esto, pero no estaba seguro. Esto es probablemente más detalles que buscados en la Q pero puede por favor colaborar en esto. –

+0

@Als: 3.2/3 * Cada programa debe contener exactamente una definición de cada función u objeto no en línea que se utiliza en ese programa; no se requiere diagnóstico. [...] Se debe definir una función en línea en cada unidad de traducción en la que se utiliza. * (Redacción de C++ 03, pero lo mismo se puede encontrar en C++ 11 donde * utilizado * es * ODR-utilizado *) –

0

static funciones (equivalentes al espacio de nombre anónimo) reciben diferentes copias para cada TU. Si la función es reentrante, esto es básicamente idéntico (algunos compiladores pueden tener diferencias de nivel de ensamblaje), pero si no lo es, tendrá diferentes datos estáticos para cada TU. Las funciones en línea están plegadas, es decir, tienen solo una copia de datos estáticos para cada TU.

+1

@TonyK: Si bien estoy de acuerdo con la sugerencia de no utilizar abreviaturas y utilizar las anotaciones completas, estoy totalmente en desacuerdo con el 'OP obviamente no es un experto'. El OP es uno de los pocos expertos en SO que realmente entiende C++ a el núcleo. –

+2

Bueno, decidí eliminar mi comentario, pero es demasiado tarde ... Permítanme repetirlo aquí: usar una abreviatura como TU supone un nivel de experiencia en su lector que hace que su explicación sea superflua. (A menos, aparentemente, su lector es FredOverflow.) Y por cierto, significa la Unidad de Traducción. – TonyK

4

Hasta donde yo sé, solo inline y las funciones de plantilla se pueden definir en archivos de encabezado.

static funciones están en desuso, y las funciones definidas en un espacio de nombre sin nombre se deben utilizar en su lugar (ver 7.3.1.1 p2). Cuando define una función en un espacio de nombre sin nombre en un encabezado, entonces cada código fuente que incluye ese encabezado (directa o indirectamente) tendrá una definición única (vea 7.3.1.1 p1). Por lo tanto, las funciones no se deben definir en el espacio de nombre sin nombre en los archivos de encabezado (solo en los archivos fuente).

Los estándares a los que se hace referencia son del estándar C++ 03.

EDIT:

siguiente ejemplo demuestra por qué las funciones y variables no deben ser definidos en espacio de nombres sin nombre en los encabezados:

ops.hpp contiene:

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

dk1 .hpp contiene:

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

dk1.cpp contiene:

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

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

dk.CPP contiene:

#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(); 
} 

Compilar como esto:

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

y la salida:

5 
22 
5 

ops la variable a es diferente para el archivo de origen dk1.cpp y dk.cpp

+0

No hay nada de malo en tener espacios de nombres anónimos con definiciones de funciones en los encabezados, no es una violación de las funciones ODR – Flexo

+0

'static' nunca se desaprobaron, solo objetos' static' (antes de C++ 11). –

+1

@awoodland: no hay nada intrínsecamente incorrecto desde el punto de vista del compilador, pero lo más probable es que exista desde el punto de vista del programa. Lo que parece ** una ** función en un encabezado es en realidad ** muchas ** funciones en diferentes unidades de traducción, generará código adicional (mayor binario, peor rendimiento de la memoria caché de instrucciones), y si la función contiene * local estático * variables, cada unidad de traducción se referirá a su propia versión. El compilador hará eso y será feliz. Pero quien necesite depurar eso en el futuro no será tan feliz. –

Cuestiones relacionadas