2011-10-20 3 views
11

Если вы хотите поместить определение функции в заголовочных файлах, оказывается есть три различных решения:кладя определения функций в файлах заголовка

  1. отметить функцию inline
  2. отметить функцию как static
  3. поместить функцию в анонимное пространство имен

(До недавнего времени я даже не знал о №1.) Итак, каковы различия между этими решениями и когда я ould Я предпочитаю, какой? Я в мире только для заголовков, поэтому мне действительно нужны определения в файлах заголовков.

+8

Вы забыли: превратите их в функциональные шаблоны. Это то, что я обычно предпочитаю. – sbi

+1

не используют статические элементы, которые приводят ко многим разным копиям и безумию. –

+2

Решение «одна копия в каждом анонимном пространстве имен» приводит к тому же безумию. – MSalters

ответ

11

static и неназванные версии пространства имен становятся одинаковыми: каждый модуль перевода будет содержать собственную версию функции, а это означает, что при заданной статической функции f указатель &f будет отличаться в каждой единицы перевода, а программа будет содержать N разные версии f (больше кода в двоичном формате).

Это не правильный подход, чтобы обеспечить в функцию в заголовке, это обеспечит N разные (точно равны) функции. Если функция содержит static местных жителей, то будет N различные static локальные переменные ...

EDIT: Для того, чтобы сделать это более четко: если то, что вы хотите, чтобы обеспечить определение функции в заголовке без нарушая правило Одного определения, правильным подходом является выполнение функции inline.

+0

Итак, 'inline' - правильный подход? Было бы хорошо, если бы вы сделали это явным. – fredoverflow

+0

Мое понимание об этом было похоже, и я опубликовал то же самое, что и ответ, но затем я удалил его. Поскольку я немного зациклился на Q, 'Как сделать функцию, определенную в заголовке, как встроенную, делает ее обход ODR?', Я думал, что' Раздел $ 3,2/5' обращается к этому, но я не был уверен. Это, вероятно, более подробная информация, чем поиск в Q, но можете ли вы это сделать. –

+0

@Als: 3.2/3 * Каждая программа должна содержать ровно одно определение каждой не-встроенной функции или объекта, которая используется в этой программе; не требуется диагностика. [...] Встроенная функция должна быть определена в каждой единицы перевода, в которой она используется. * (Формулировка из C++ 03, но то же самое можно найти в C++ 11, где * used * is * ODR-used *) –

0

static функции (эквивалентные анонимному пространству имен) получают разные копии для каждого ТУ. Если функция является повторной, это в основном идентично (некоторые компиляторы могут иметь разницу на уровне сборки), но если это не так, то для каждой ТУ она будет иметь разные статические данные. Встроенные функции свернуты, то есть они имеют только одну копию статических данных для каждого ТУ.

+1

@TonyK: Хотя я согласен с предложением не использовать аббревиатуры и использовать полные обозначения, я категорически не согласен с тем, что «OP явно не является экспертом». OP является одним из немногих экспертов в SO, который действительно понимает C++ для ядро. –

+2

Ну, я решил удалить свой комментарий, но слишком поздно ... Поэтому позвольте мне переформулировать его здесь: Использование аббревиатуры типа TU предполагает уровень вашего читателя, который делает ваше объяснение излишним. (Если, видимо, ваш читатель FredOverflow.) И BTW, это означает Translation Unit. – TonyK

4

Насколько я знаю, только inline и функции шаблона могут быть определены в заголовочных файлах.

static функции устарели, и вместо них следует использовать функции, определенные в неназванном пространстве имен (см. 7.3.1.1 p2). Когда вы определяете функцию в неназванном пространстве имен в заголовке, каждый исходный код, включающий этот заголовок (прямо или косвенно), будет иметь уникальное определение (см. 7.3.1.1 p1). Поэтому функции не должны определяться в неназванном пространстве имен в файлах заголовков (только в исходных файлах).

Стандарт, на который даны ссылки, относится к стандарту C++ 03.

РЕДАКТИРОВАТЬ:

Следующий пример демонстрирует, почему функции и переменные не должны быть определены в пространстве имен безымянного в заголовках:

ops.hpp содержит:

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

DK1 .hpp содержит:

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

dk1.cpp содержит:

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

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

дк.каст содержит:

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

Compile так:

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

и выход:

5 
22 
5 

опс переменная a отличается для исходного файла dk1.cpp и dk.cpp

+0

Нет ничего плохого в том, что у вас есть анонимные пространства имен с определениями функций в заголовках - это не является нарушением ODR – Flexo

+0

'static' никогда не устарели, а только' static' (до C++ 11). –

+1

@awoodland: Нет ничего изначально неправильного с точки зрения компилятора, но, скорее всего, с точки зрения программы. То, что выглядит как ** ** функция в заголовке, на самом деле ** много ** функций в разных единицах перевода, будет генерировать дополнительный код (больший двоичный код, худшая производительность кэша команд), а если функция содержит * локальный статический * переменные, каждая единица перевода будет ссылаться на свою собственную версию. Компилятор сделает это и будет счастлив. Но тот, кто должен отлаживать это в будущем, не будет так счастлив. –

Смежные вопросы