**13.** Ayırmak için boşluk kullanmayın `[]` operatör.
**14.** İn a `template <...>` ifade, arasında bir boşluk kullanın `template` ve `<`; sonra boşluk yok `<` ya da önce `>`.
``` cpp
template <typenameTKey,typenameTValue>
struct AggregatedStatElement
{}
```
**15.** Sınıflarda ve yapılarda, yazın `public`, `private`, ve `protected` aynı seviyede `class/struct` ve kodun geri kalanını girinti.
``` cpp
template <typenameT>
class MultiVersion
{
public:
/// Version of object for usage. shared_ptr manage lifetime of version.
using Version = std::shared_ptr<constT>;
...
}
```
**16.** Eğer aynı`namespace` tüm dosya için kullanılır ve başka önemli bir şey yoktur, içinde bir ofset gerekli değildir `namespace`.
**17.** Eğer blok için bir `if`, `for`, `while` veya başka bir ifade tek bir `statement`, kıvırcık parantez isteğe bağlıdır. Place the `statement` bunun yerine ayrı bir satırda. Bu kural iç içe geçmiş için de geçerlidir `if`, `for`, `while`, …
Ama eğer iç `statement` kıvırcık parantez içerir veya `else`, dış blok kıvırcık parantez içinde yazılmalıdır.
``` cpp
/// Finish write.
for (auto & stream : streams)
stream.second->finalize();
```
**18.** Çizgilerin uçlarında boşluk olmamalıdır.
**19.** Kaynak dosyalar UTF-8 kodlanmıştır.
**20.** ASCII olmayan karakterler dize değişmezlerinde kullanılabilir.
Not: bu yorumlardan belgeler oluşturmak için Doxygen kullanabilirsiniz. Ancak DOXYGEN genellikle kullanılmaz, çünkü IDE'DEKİ kodda gezinmek daha uygundur.
**10.** Dosya adları, içerikleriyle aynı stili kullanmalıdır.
Bir dosya tek bir sınıf içeriyorsa, dosyayı sınıfla aynı şekilde adlandırın (CamelCase).
Dosya tek bir işlev içeriyorsa, dosyayı işlevle aynı şekilde adlandırın (camelCase).
**11.** İsim bir kısaltma içeriyorsa, o zaman:
- Değişken adları için kısaltma küçük harfler kullanmalıdır `mysql_connection` (değil `mySQL_connection`).
- Sınıfların ve işlevlerin adları için, büyük harfleri kısaltmada tutun`MySQLConnection` (değil `MySqlConnection`).
**12.** Yalnızca sınıf üyelerini başlatmak için kullanılan yapıcı bağımsız değişkenleri, sınıf üyeleri ile aynı şekilde, ancak sonunda bir alt çizgi ile adlandırılmalıdır.
``` cpp
FileQueueProcessor(
const std::string & path_,
const std::string & prefix_,
std::shared_ptr<FileHandler> handler_)
: path(path_),
prefix(prefix_),
handler(handler_),
log(&Logger::get("FileQueueProcessor"))
{
}
```
Bağımsız değişken yapıcı gövdesinde kullanılmazsa, alt çizgi soneki atlanabilir.
**13.** Yerel değişkenlerin ve sınıf üyelerinin adlarında fark yoktur (önek gerekmez).
**14.** Bir de SAB theitler için `enum`, büyük harfle CamelCase kullanın. ALL_CAPS da kabul edilebilir. Eğer... `enum` yerel olmayan, bir `enum class`.
Kısaltılmış versiyon ortak kullanım ise eksik kelimeler kabul edilebilir.
Yorumlarda tam ad yanında yer alıyorsa bir kısaltma da kullanabilirsiniz.
**17.** C++ kaynak kodu ile dosya adları olmalıdır `.cpp` uzantı. Başlık dosyaları olmalıdır `.h` uzantı.
## Kod nasıl yazılır {#how-to-write-code}
**1.** Bellek yönetimi.
El ile bellek ayırma (`delete`) sadece kütüphane kodunda kullanılabilir.
Kütüphane kod inunda, `delete` operatör yalnızca yıkıcılarda kullanılabilir.
Uygulama kodunda, bellek sahibi olan nesne tarafından serbest bırakılmalıdır.
Örnekler:
- En kolay yol, bir nesneyi yığına yerleştirmek veya onu başka bir sınıfın üyesi yapmaktır.
- Çok sayıda küçük nesne için kapları kullanın.
- Öbekte bulunan az sayıda nesnenin otomatik olarak ayrılması için şunları kullanın `shared_ptr/unique_ptr`.
**2.** Kaynak yönetimi.
Kullanmak `RAII` ve yukarıya bakın.
**3.** Hata işleme.
İstisnaları kullanın. Çoğu durumda, yalnızca bir istisna atmanız gerekir ve onu yakalamanız gerekmez (çünkü `RAII`).
Çevrimdışı veri işleme uygulamalarında, istisnaları yakalamamak genellikle kabul edilebilir.
Kullanıcı isteklerini işleyen sunucularda, bağlantı işleyicisinin en üst düzeyindeki istisnaları yakalamak genellikle yeterlidir.
İş parçacığı işlevlerinde, bunları ana iş parçacığında yeniden taramak için tüm istisnaları yakalamalı ve tutmalısınız `join`.
``` cpp
/// If there weren't any calculations yet, calculate the first block synchronously
if (!started)
{
calculate();
started = true;
}
else /// If calculations are already in progress, wait for the result
pool.wait();
if (exception)
exception->rethrow();
```
İşleme olmadan istisnaları asla gizlemeyin. Sadece körü körüne log tüm istisnaları koymak asla.
``` cpp
//Not correct
catch (...) {}
```
Eğer bazı özel durumlar göz ardı etmek gerekiyorsa, sadece özel olanlar için bunu yapmak ve diğerleri yeniden oluşturma.
``` cpp
catch (const DB::Exception & e)
{
if (e.code() == ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION)
return nullptr;
else
throw;
}
```
Yanıt kodlarıyla işlevleri kullanırken veya `errno`, her zaman sonucu kontrol edin ve hata durumunda bir istisna atın.
``` cpp
if (0 != close(fd))
throwFromErrno("Cannot close file " + file_name, ErrorCodes::CANNOT_CLOSE_FILE);
```
`Do not use assert`.
**4.** İstisna türleri.
Uygulama kodunda karmaşık özel durum hiyerarşisini kullanmaya gerek yoktur. Özel durum metni bir sistem yöneticisi için anlaşılabilir olmalıdır.
**5.** Yıkıcılardan istisnalar atmak.
Bu tavsiye edilmez, ancak izin verilir.
Aşağıdaki seçenekleri kullanın:
- Bir işlev oluşturma (`done()` veya `finalize()`) bu, bir istisnaya yol açabilecek tüm işleri önceden yapacaktır. Bu işlev çağrıldıysa, daha sonra yıkıcıda istisna olmamalıdır.
- Çok karmaşık olan görevler (ağ üzerinden ileti gönderme gibi), sınıf kullanıcısının imha edilmeden önce çağırması gereken ayrı bir yöntemle yerleştirilebilir.
- Yıkıcıda bir istisna varsa, onu gizlemek yerine günlüğe kaydetmek daha iyidir (logger mevcutsa).
- Basit uygulamalarda, güvenmek kabul edilebilir `std::terminate` bu (vakaların `noexcept` varsayılan olarak C++11) istisnaları işlemek için.
**6.** Anonim kod blokları.
Belirli değişkenleri yerel hale getirmek için tek bir işlevin içinde ayrı bir kod bloğu oluşturabilirsiniz, böylece bloktan çıkarken yıkıcılar çağrılır.
``` cpp
Block block = data.in->read();
{
std::lock_guard<std::mutex> lock(mutex);
data.ready = true;
data.block = block;
}
ready_any.set();
```
**7.** Multithreading.
Çevrimdışı veri işleme programlarında:
- Tek bir CPU çekirdeğinde mümkün olan en iyi performansı elde etmeye çalışın. Daha sonra gerekirse kodunuzu parallelize edebilirsiniz.
Sunucu uygulamalarında:
- İstekleri işlemek için iş parçacığı havuzunu kullanın. Bu noktada, userspace bağlam değiştirme gerektiren herhangi bir görevimiz olmadı.
Çatal paralelleştirme için kullanılmaz.
**8.** İş parçacıklarını senkronize etme.
Genellikle farklı iş parçacıklarının farklı bellek hücreleri kullanmasını sağlamak mümkündür (daha da iyisi: farklı önbellek çizgileri) ve herhangi bir iş parçacığı senkronizasyonu kullanmamak (hariç `joinAll`).
Senkronizasyon gerekiyorsa, çoğu durumda, mutex altında kullanmak yeterlidir `lock_guard`.
Diğer durumlarda sistem senkronizasyonu ilkellerini kullanın. Meşgul bekleme kullanmayın.
Atomik işlemler sadece en basit durumlarda kullanılmalıdır.
Birincil uzmanlık alanınız olmadığı sürece kilitsiz veri yapılarını uygulamaya çalışmayın.
**9.** İşaretçiler vs referanslar.
Çoğu durumda, referansları tercih edin.
**10.** const.
Sabit referanslar, sabitler için işaretçiler kullanın, `const_iterator` ve const yöntemleri.
Düşünmek `const` varsayılan olmak ve olmayan kullanmak-`const` sadece gerektiğinde.
Değişkenleri değere göre geçirirken, `const` genellikle mantıklı değil.
**11.** imzasız.
Kullanmak `unsigned` gerekirse.
**12.** Sayısal türleri.
Türleri kullanın `UInt8`, `UInt16`, `UInt32`, `UInt64`, `Int8`, `Int16`, `Int32`, ve `Int64` gibi `size_t`, `ssize_t`, ve `ptrdiff_t`.
Bu türleri sayılar için kullanmayın: `signed/unsigned long`, `long long`, `short`, `signed/unsigned char`, `char`.
**13.** Argümanları geçmek.
Karmaşık değerleri referansla geçirin (dahil `std::string`).
Bir işlev öbekte oluşturulan bir nesnenin sahipliğini yakalarsa, bağımsız değişken türünü yapın `shared_ptr` veya `unique_ptr`.
**14.** Değerleri döndürür.
Çoğu durumda, sadece kullanın `return`. Yaz domayın `[return std::move(res)]{.strike}`.
İşlev öbek üzerinde bir nesne ayırır ve döndürürse, şunları kullanın `shared_ptr` veya `unique_ptr`.
Nadir durumlarda, değeri bir argüman aracılığıyla döndürmeniz gerekebilir. Bu durumda, argüman bir referans olmalıdır.
``` cpp
using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;
/** Allows creating an aggregate function by its name.
Ayrı bir kullanmaya gerek yoktur `namespace` uygulama kodu için.
Küçük kütüphanelerin de buna ihtiyacı yok.
Orta ve büyük kütüphaneler için her şeyi bir `namespace`.
Kütüphan theede `.h` dosya, kullanabilirsiniz `namespace detail` uygulama kodu için gerekli olmayan uygulama ayrıntılarını gizlemek için.
İn a `.cpp` dosya, bir kullanabilirsiniz `static` veya sembolleri gizlemek için anonim ad alanı.
Ayrıca, bir `namespace` bir için kullanılabilir `enum` ilgili isimlerin harici bir yere düşmesini önlemek için `namespace` (ama kullanmak daha iyidir `enum class`).
**16.** Ertelenmiş başlatma.
Başlatma için bağımsız değişkenler gerekiyorsa, normalde varsayılan bir yapıcı yazmamalısınız.
Daha sonra başlatmayı geciktirmeniz gerekiyorsa, geçersiz bir nesne oluşturacak varsayılan bir yapıcı ekleyebilirsiniz. Veya, az sayıda nesne için şunları kullanabilirsiniz `shared_ptr/unique_ptr`.
**2.** Gerekirse, OS paketinde bulunan iyi bilinen kütüphaneleri kullanabilirsiniz.
Zaten mevcut olan iyi bir çözüm varsa, başka bir kütüphane yüklemeniz gerektiği anlamına gelse bile kullanın.
(Ancak kötü kütüphaneleri koddan kaldırmaya hazır olun .)
**3.** Paketlerde ihtiyacınız olan şey yoksa veya eski bir sürüme veya yanlış derleme türüne sahip değilseniz, paketlerde olmayan bir kitaplık yükleyebilirsiniz.
**4.** Kütüphane küçükse ve kendi karmaşık yapı sistemine sahip değilse, kaynak dosyaları`contrib` klasör.
**5.** Tercih her zaman zaten kullanımda olan kütüphanelere verilir.
## Genel Öneriler {#general-recommendations-1}
**1.** Mümkün olduğunca az kod yazın.
**2.** En basit çözümü deneyin.
**3.** Nasıl çalışacağını ve iç döngünün nasıl çalışacağını bilene kadar kod yazmayın.
**4.** En basit durumlarda, kullanın `using` sınıflar veya yapılar yerine.
**5.** Mümkünse, kopya oluşturucuları, atama işleçleri, yıkıcılar (sınıf en az bir sanal işlev içeriyorsa, sanal bir işlev dışında) yazmayın, oluşturucuları taşıyın veya atama işleçlerini taşıyın. Başka bir deyişle, derleyici tarafından oluşturulan işlevleri düzgün çalışması gerekir. Kullanabilirsiniz `default`.
**6.** Kod sadeleştirme teşvik edilir. Mümkünse kodunuzun boyutunu azaltın.
## Ek Öneriler {#additional-recommendations}
**1.** Açıkça belirtme `std::` türleri için `stddef.h`
tavsiye edilmez. Başka bir deyişle, yazmanızı öneririz `size_t` yerine `std::size_t` daha kısa olduğu için.
Eklemek kabul edilebilir `std::`.
**2.** Açıkça belirtme `std::` standart C kitap fromlığından fonksiyonlar için
tavsiye edilmez. Başka bir deyişle, yazın `memcpy` yerine `std::memcpy`.
Bunun nedeni, aşağıdaki gibi benzer standart dışı işlevlerin olmasıdır `memmem`. Bu işlevleri zaman zaman kullanıyoruz. Bu işlevler mevcut değil `namespace std`.
Yazar yousan `std::memcpy` yerine `memcpy` her yerde, o zaman `memmem` olarak `std::` garip görünecek.
Yine de, hala kullanabilirsiniz `std::` eğer tercih ederseniz edin.