One Definition Rule (ODR), C++'in temel bir kuralıdır ve programın tümü (tüm çeviri birimleri) içerisinde her nesne, işlev veya sınıf için tam olarak bir tanımlama (definition) olmasını gerektirir.
ODR, aşağıdaki durumlarda ihlal edilir:
Bu, yakalanması zor, öngörülemez hatalara, hatalı bağlantıya veya daha kötüsü, programın derleme biçimine bağlı olarak farklı davranmasına yol açar.
Neden ihlal edilir:
Büyük projelerde genellikle .h dosyaları versiyon kontrolü olmaksızın kopyalanır/ değiştirilir veya kod birçok modüle ayrılır. Eğer biri inline işlevini sadece bir yerde değiştirirse, diğer kaynak dosyaları eski versiyonu içerebilir.
Nasıl kaçınılır:
constexpr veya C++17 ile inline değişkenlerini kullanın.Aynı isimde ve farklı tanımlamaya sahip static işlevler (static void foo()) farklı .cpp dosyalarında tanımlanabilir mi?
Birçok kişi static işlevlerin modüller arasında birbirini etkilemeyeceğini düşünmektedir. Cevap: evet, çünkü her biri kendi çeviri biriminde görünür (internal linkage). Ancak inline işlevler ve şablonlar için bu garanti edilir değil; bu sıkça karıştırılır.
Örnek:
// file1.cpp static void foo() { std::cout << "A"; } // file2.cpp static void foo() { std::cout << "B"; }
Bu modüllerdeki çağrılar bağımsız olacaktır.
Hikaye
Büyük bir projede bir geliştirici, bir kopya .h dosyasının içinde inline işlevinin gövdesini yalnızca birinde değiştirdi. Derlemeden sonra bazı davranışlar öngörülemez hale geldi: bazı modüller eski algoritma ile, bazıları ise yeni ile çalıştı. Sebep — inline işlev için ODR ihlali.
Hikaye
C++17'ye geçişte, sabit değişken birden fazla başlık dosyasında inline anahtar kelimesi kullanılmadan tanımlandı. Bağlama sırasında birçok duplicate symbol hatası ortaya çıktı.
inline constdeğişkenini tanımlayarak düzeltildi.
Hikaye
Geç derlenmiş bir sistem .h dosyası, şablon sınıfının aynı yönteminin iki tanımını içeriyordu; bunlar farklı derlemelerde bir ifdef kontrolü ile farklılık gösteriyordu. Daha sonra uygulama, bağlı modüller arasında ABI tutarsızlığı nedeniyle dönemsel olarak çöküyordu.