C++11'den önce bu kural Rule of Three olarak ele alınmış ve C++11'le gelen taşıma (move) semantiği ile kurala ilişkin işlev sayısı artmıştır. Bu kural bir sınıf tanımı içinde birbiriyle ilişkili toplamda 6 özel işleve ilişkindir. Bunlar;
- default constructor
- copy constructor //rule of three
- copy assignment operator //rule of three
- destructor //rule of three
- move constructor //rule of five
- move assignment operator //rule of five
Bu eforlardan birisi bizim yazdığımız özel fonksiyonlarla birlikte derleyicinin neleri yazıp yazmayacağı ya da delete edeceği sorunsalıdır. Derleyici bu noktada bizim sınıf tanımı içerisinde yazdığımız özel fonksiyonlara göre hareket etmektedir. Aşağıda bununla ilgili kural matrisini görebiliriz.
user-declared & implicitly-declared matrisi |
Yukarıdaki matristen bir kaç okuma yapmak istersek; Bir sınıfın sonlandırıcı fonksiyonu bildirilirse derleyici sınıfın taşıma fonksiyonlarıyla (move members) ilgili bildirim yapmaz bunun dışındaki tüm özel işlevlerin varsayılan edileceği matrisin 5. satırında görülebilir.
- Car() = default;
- Car(const Car &) = default;
- Car &operator=(const Car &) = default;
- Car() = default;
- ~Car() = default;
- Car(const Car &) = delete;
- Car &operator=(const Car &) = delete;
- ~Car() = default;
- Car &operator=(const Car &) = default;
Örnek - 1 : Kaynak Kod |
Özetle bu kural eğer birini bildiriyorsanız bu özel fonksiyonların tamamı ile ilgili bildirimleri gerçekleştirin ve karmaşadan kurtulun sonucuna varabiliriz. Yukarıdaki örnekte tam bu kurala uygun şekilde gerçekleştirilmiştir.
Örnek - 1 : Çıktı |
Note:
- Derleyici için neler bildirim olarak niteleniyor dersek? Aşağıdaki 4 durum da kullanıcı bildirimi olarak nitelendirilmektedir.
X() {} //user-declared
X(); //user-declared
X() = default; //user-declared
X() = delete; //user-declared
- Sadece kopyalanabilen (Copyable Objects) objeler söz konusu olduğunda
- Otomatik kaynak yönetimi kullanılıyorsa: The Rule of Zero.
- Manuel kaynak yönetimi kullanılıyorsa: The Rule of Three.
- Hep kopyalanabilen hem taşınabilen (Moveable Objects) objeler söz konusu olduğunda
- Otomatik kaynak yönetimi kullanılıyorsa: The Rule of Zero.
- Manuel kaynak yönetimi kullanılıyorsa: The Rule of Five.
- Taşınamayan Nesneler (Unmoveable Objects)
Bir nesnenin taşınarak hayata başlanmasını istemiyorsak move constructor'ın delete edilmesi gerekmektedir.Örnek: Car(Car&& source) = delete;
Bir nesneye taşıma yoluyla atama yapılmasını istemiyorsak move assignment operator'ın delete edilmesi gerekmektedir.Örnek: Car& operator=(Car&& rhs) = delete;
- Kopyalanamayan Nesneler (Uncopyable Objects)
Bir nesnenin kopyalanarak hayata başlanmasını istemiyorsak copy constructor'ın delete edilmesi gerekmektedir.Örnek: Car(const Car& kSource) = delete;
Bir nesneye kopyalanarak atama yapılmasını istemiyorsak copy assignment operator'ün delete edilmesi gerekmektedir.Örnek: Car& operator=(const Car& kRhs) = delete;