Что такое "Правило одного определения"?
Правило одного определения (One definition rule или ODR) состоит из нескольких пунктов:
Единица трансляции не может содержать больше одного определения
struct
),Программа должна содержать ровно одно определение:
inline
функции,Переменная считается "ODR-использованной" (odr-used), если она находится в потенциально вычисляемом выражении. Здесь есть некоторые исключения, но они не интересны в контексте самого правила одного определения.
Под "программой" понимается ее исходный код, а также стандартная и пользовательские библиотеки. Компилятор не обязан выдавать какие-либо ошибки или предупреждения, если это правило нарушено.
Все inline
функции должны быть определены в каждой единице трансляции, где они ODR-использованы.
Единица трансляции должна содержать ровно одно определение класса, если он был использован таким образом, что его тип должен быть полным.
Программа может содержать несколько определений
inline
функции с внешним связыванием,static
функции,если они находятся в разных единицах трансляции и удовлетворяют следующим условиям:
Если это правило соблюдено, программа будет вести себя так, как будто в ней было только одно определение. В противном случае поведение программы не определено.
ODR-использованные переменные
// Единица трансляции 1: | // Единица трансляции 2:
int x = 1; | int x = 1;
int y = 1; | int y = 1;
decltype(x) xx; // ОК, "x" использована в не-вычисляемом контексте.
int z = y; // нарушение ODR, "y" определена в двух единицах трансляции и ODR-использована.
Нарушение правила 4 (разные конструкторы базового класса)
// Единица трансляции 1: | // Единица трансляции 2:
struct X { | struct X {
X(int); | X(int);
X(int, int); | X(int, int);
}; | };
|
X::X(int = 0) { } | X::X(int = 0, int = 0) { }
|
class D: public X { }; | class D: public X { };
Неявно определенный конструктор D::D()
нарушает ODR - в одном случае он использует X(int)
, а в другом - X(int, int)
Более простой случай нарушения ODR:
// g.h
void f(float t);
inline void g() { f(1); }
---------------------------------------------------------------------
// f_int.h
void f(int);
--------------------------------+------------------------------------
// main.cpp | // f.cpp
#include "g.h" | #include "f_int.h"
| #include "g.h"
int main() { |
g(); | void f(int) {}
} | void f(float t) {}
Функция g
вызывает разные функции f
в разных единицах трансляции.
Это нарушает пункт "имена ... должны относиться к одним и тем же сущностям".
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
После появления запроса на ввод чисел программа вылет с такой ошибкой: Segmentation fault (core dumped)
Добрый день! У меня такая проблема компилирую exe, который необходимо запустить с флеш носителя на другом PCПри запуске, АВ Avast пропускает исполняемый...
Я считываю строку, состоящую из чисел, разделенных различными символами, как удалить из строки все символы, заменив их на пробелы(хочу посчитать...
Привет! Помогите пожалуйста с создать алгоритм для суммы произведенийДолжен быть цикл в цикле, первый сделал (произведение), а как теперь...