Directrices de codificación en C++

Mejores prácticas

  1. NUNCA incluir declaraciones using namespace en archivos de encabezado.

  2. NUNCA incluir una declaración de uso para el espacio de nombres estándar (std). En su lugar, calificar siempre todos los tipos provenientes de él.

  3. UTILIZAR una expresión constexpr en lugar de una MACRO siempre que sea posible.

  4. UTILIZAR pragma once en lugar de guardias de encabezado.

  5. UTILIZAR enum class en lugar de enum siempre que sea posible.

  6. SIEMPRE declarar variables lo más cerca posible de su primer uso, ¡esto no es C!

  7. SIEMPRE pasar parámetros no triviales por referencia.

  8. PREFERIR un valor de retorno compuesto (por ejemplo, pair, struct POD) a múltiples parámetros de salida.

  9. PREFERIR auto siempre que sea posible, pero usar tantos modificadores de tipo (const, volatile, &, *) como sea posible.

  10. EVITAR volatile a menos que haya una justificación muy fuerte (generalmente no la hay).

  11. SIEMPRE utilizar declaraciones using en lugar de typedef para alias.

  12. UTILIZAR calificadores de función (override, final, const) libremente.

  13. PREFERIR una enumeración a múltiples booleanos.

  14. UTILIZAR espacios de nombres anónimos con libertad en archivos cpp y exportar el número mínimo de nombres desde cada objeto de compilación.

  15. NUNCA utilizar funciones libres estáticas.

Tipos numéricos

  1. UTILIZAR size_t siempre que se trate de tamaños de datos.

  2. UTILIZAR tipos definidos en stdint.h (uint8_t, uint16_t, uint32_t, etc.).

  3. EVITAR el uso de tipos con signo a menos que sea realmente necesario y razonable.

  4. EVITAR el uso de aritmética de punto flotante, especialmente en cualquier parte del consenso.

Estructura de archivos / directorios

Si un archivo cpp/h contiene una sola clase, el archivo debe tener el nombre de la clase y estar en UpperCamelCase. Si un archivo cpp/h contiene funciones de utilidad, el archivo debe tener un nombre descriptivo y estar en UpperCamelCase.

Esperamos jerarquías paralelas de directorios de código fuente y pruebas. Por ejemplo,

root
- parser  # package name, directory containing source code
  Parser.h/cpp  # contains class Parser
  - ast
    - Ast.h/cpp  # contains various exports

- tests  # directory containing tests for source code
  - ParserTests.cpp  # unit tests for parser/Parser.h/cpp
  - ast
    - AstTests.cpp  # unit tests for parser/ast/Ast.h/cpp

Denominación

  1. Las funciones estáticas y libres deben ser UpperCamelCase

  2. Los nombres de las funciones miembro deben ser minúsculasCamelCase

  3. Las constantes (globales o locales) deben ser Upper_Camel_Case.

  4. #defines debe ser TITLE_CASE

  5. Las variables locales y los parámetros de función deben ser lowerCamelCase

  6. Los miembros de la estructura deben ser UpperCamelCase

Prefixes

  1. Prefije los miembros de la instancia de clase con m_

  2. Prefije los miembros estáticos de la clase con s_

  3. Prefijo globales con g_

  4. Prefije todos los punteros (tanto inteligentes como sin formato) con p

  5. Nunca anteponga nada con un solo guión bajo (_).

Arreglos

Si pasa el tamaño de una matriz en alguna parte, siempre asigne un nombre a la variable de tamaño, que sugiera lo que realmente es:

  1. Entonces, si realmente espera número de elementos, use el nombre con el postfijo Count [p. ej. recuento de nodos]

  2. Si desea una cantidad de bytes, use un nombre como size_t nameSize

Incluye

  1. Utilice siempre “/” en incluye y NUNCA “\”, (estándar C WG14/N1256 punto 6.4.7, estándar C++ ISO/IEC 14882:2003 punto 2.8, estándar C++ ISO/IEC 14882:2011 (del borrador de trabajo N3225) punto 2.9)

  2. Intente incluir la cantidad mínima de archivos necesarios para una compilación exitosa. Corolario: no incluyas nada que no necesites.

  3. El orden incluye desde lo más específico hasta lo más general.

Estilo

Clases, Métodos y Miembros

Orden de clase recomendado:

  1. Constantes privadas (ya que generalmente se usan temprano)

  2. Constantes públicas

  3. Métodos

    1. Constructores

    2. Métodos de instancia

    3. Métodos estáticos

  4. Campos

    1. Miembros públicos (probablemente deberían usarse solo para tipos de POD)

    2. Miembros protegidos

    3. Miembros privados

Utilice un modificador de acceso (público:, privado:) para cada sección, incluso si el modificador es redundante.

Nombres especiales

  • Cadena de bloques no cadena de bloques

  • Nombre de archivo no Nombre de archivo

  • Sistema de archivos no Sistema de archivos

  • No vacío no no vacío

  • Distinto de cero no distinto de cero ni de cero ni de cero

  • Ida y vuelta no Ida y vuelta

  • Subcaché no subcaché

  • ThreadPool no Threadpool

  • Marca de tiempo no Marca de tiempo

  • Configuración para nombres de clases

  • config para nombres de variables

margen adicional

sangría única para apertura de bloque

for (auto&& pEntity : entities) {
    singleEntityVector[0] = pEntity;
    auto result = dispatcher.dispatch(m_config.ValidationPolicy, singleEntityVector);
    m_config.pObserver->notify(*pEntity, observerContext);
}

las continuaciones usan sangría doble

BITXORCORE_LOG(debug) << "comparing chain scores: " << localScore << " (local) vs "
        << remoteScore << " (remote)";
return pState
        && pState->ImportanceInfo.Importance > Importance(0)
        && pState->Balances.get(Xem_Id) >= minHarvestingBalance;

la lista de inicializadores y los argumentos de factores/funciones/métodos tienen una sangría doble

// mind the double indent for method arguments
thread::future<std::unique_ptr<model::Block>> BlockAt(
        Height height,
        const io::BlockStorageView& storage) {
    if (Height(0) == height || storage.chainHeight() < height) {
        auto exception = CreateHeightException("unable to get block at height", height);
        return thread::make_exceptional_future<std::unique_ptr<model::Block>>(exception);
    }

    return thread::make_ready_future(storage.loadBlock(height));
}

Vigorizante

empty body, short

Foo() : m_value(0)
{}

empty body, long

// two indents
Foo(very arguments, much wow)
        : m_value(0)
        , m_xman(professor)
{}

body, short

Foo() : m_value(0) {
    // body
}

body, long

// two indents
Foo(very arguments, much wow)
        : m_value(0)
        , m_xman(professor) {
    // body
}

Declaraciones vacías

  • No use tal construcción cuando for no tiene un cuerpo

    for (a; b; c);
    

    Instead use

    for (a; b; c)
    {}
    

    Esto deja clara la intención de lo que tenías en mente.