Правило одного визначення
Правило одного визначення (One Definition Rule, ODR) — важлива конценція в мові програмування C++, що визначена в ISO C++ Standard(ISO/IEC 14882) 2003, в розділі 3.2.
Коротко ODR стверджує:
- В окремій одиниці трансляції (файлі, якщо конкретна реалізація зберігає тексти програм в файлах, після обробки препроцесором) шаблон, клас, функція, об'єкт, або перерахування можуть мати не більше одного визначення. Хоча деякі можуть мати яку завгодно кількість оголошень.
- В програмі об'єкт або невставна функція не можуть мати більш ніж одне визначення. Якщо об'єкт чи непідставна функція не використовуються, тоді достатньо оголошення без визначення. У випадку використання вони повинні мати рівно одне визначення.
- Деякі сутності, наприклад, класи, шаблони або підставні функції можуть мати більше ніж одне визначення тільки якщо:
- вони знаходяться в різних одиницях трансляції;
- вони ідентичні лексема за лексемою;
- значення лексем однаково в обох одиницях трансляції;
Компілятори не завжди знаходять порушення ODR. Багато з них виявляються вже компонувальником.
Приклади
//file 1.c
struct S { int a; char b; };
void f(S*);
//file 2.c
struct S { int a; char b; };
void f(S*) { /* ... */ };
Правило ODR каже, що цей приклад дозволений, і в обох файл під S буде матися на увазі одна і та сама структура. Хоча це й нерозумний спосіб описання структур, через те що людина яка супроводжує file2.c може допустити, що визначення в її файлі єдине і буд вважати себе в праві змінювати його, що може призвести до помилок, які буде важко знайти.
Метою ODR є реалізація можливості включення визначення класу в різні одиниці трансляції із одного заголовного файлу.
//file s.h
struct S { int a; char b; };
void f(S*);
//file 1.c
#include "s.h"
// використання f()
//file 1.c
#include "s.h"
void f(S*) { /* ... */ };
Наведемо приклад трьох способів порушення правила ODR:
//file 1.c
struct S1 { int a; char b; };
struct S1 { int a; char b; }; // помилка: повторне визначення
Структуру не можна двічі визначити в одному файлі.
//file 1.c
struct S2 { int a; char b; };
//file 1.c
struct S2 { int a; char bb; }; // помилка
Не ідентичні лексема за лексемою.
//file 1.c
typedef int X;
struct S3 { X a; char b; };
//file 2.c
typedef char X;
struct S3 { X a; char b; }; // помилка
Значення лексем різне в різних одиницях трансляції.
Джерела
- Мова програмування С++ by Bjarne Stroustrup — Addison-Wesley Pub Co; 3rd edition (February 15, 2000); ISBN 0-201-70073-5