As recomendações a seguir não são requisitos.
Se você estiver editando código, faz sentido seguir a formatação já existente.
O estilo de código é necessário para manter a consistência. A consistência facilita a leitura do código e também a pesquisa nele.
Muitas das regras não têm uma justificativa lógica; elas são ditadas por práticas consolidadas.
1. A maior parte da formatação é feita automaticamente pelo clang-format.
2. A indentação é de 4 espaços. Configure seu ambiente de desenvolvimento para que uma tabulação insira quatro espaços.
3. As chaves de abertura e fechamento devem ficar em uma linha separada.
inline void readBoolText(bool & x, ReadBuffer & buf)
{
char tmp = '0';
readChar(tmp, buf);
x = tmp != '0';
}
4. Se o corpo inteiro da função for um único statement, ele pode ser colocado em uma única linha. Coloque espaços ao redor das chaves (além do espaço no final da linha).
inline size_t mask() const { return buf_size() - 1; }
inline size_t place(HashValue x) const { return x & mask(); }
5. Para funções. Não coloque espaços ao redor dos parênteses.
void reinsert(const Value & x)
memcpy(&buf[place_value], &x, sizeof(x));
6. Em expressões if, for, while e outras, um espaço é inserido antes do parêntese de abertura (ao contrário das chamadas de função).
for (size_t i = 0; i < rows; i += storage.index_granularity)
7. Adicione espaços ao redor dos operadores binários (+, -, *, /, %, …) e do operador ternário ?:.
UInt16 year = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
UInt8 month = (s[5] - '0') * 10 + (s[6] - '0');
UInt8 day = (s[8] - '0') * 10 + (s[9] - '0');
8. Se uma quebra de linha for inserida, coloque o operador em uma nova linha e aumente a indentação antes dele.
if (elapsed_ns)
message << " ("
<< rows_read_on_server * 1000000000 / elapsed_ns << " rows/s., "
<< bytes_read_on_server * 1000.0 / elapsed_ns << " MB/s.) ";
9. Você pode usar espaços para alinhamento dentro de uma linha, se quiser.
dst.ClickLogID = click.LogID;
dst.ClickEventID = click.EventID;
dst.ClickGoodEvent = click.GoodEvent;
10. Não use espaços ao redor dos operadores ., ->.
Se necessário, o operador pode ser quebrado para a próxima linha. Nesse caso, o recuo antes dele é aumentado.
11. Não use espaço para separar operadores unários (--, ++, *, &, …) do argumento.
12. Coloque um espaço após uma vírgula, mas não antes dela. A mesma regra vale para um ponto e vírgula dentro de uma expressão for.
13. Não use espaços para separar o operador [].
14. Em uma expressão template <...>, use um espaço entre template e <; sem espaços após < ou antes de >.
template <typename TKey, typename TValue>
struct AggregatedStatElement
{}
15. Em classes e estruturas, escreva public, private e protected no mesmo nível de class/struct, e indente o restante do código.
template <typename T>
class MultiVersion
{
public:
/// Versão do objeto para uso. shared_ptr gerencia o tempo de vida da versão.
using Version = std::shared_ptr<const T>;
...
}
16. Se o mesmo namespace for usado em todo o arquivo e não houver mais nada significativo, a indentação dentro do namespace não é necessária.
17. Se o bloco de um if, for, while ou outra expressão consistir em um único statement, as chaves são opcionais. Coloque o statement em uma linha separada. Essa regra também é válida para if, for, while aninhados, …
Mas se o statement interno contiver chaves ou else, o bloco externo deverá ser escrito entre chaves.
/// Finalizar escrita.
for (auto & stream : streams)
stream.second->finalize();
18. Não deve haver espaços ao final das linhas.
19. Os arquivos fonte são codificados em UTF-8.
20. Caracteres não ASCII podem ser usados em literais de string.
<< ", " << (timer.elapsed() / chunks_stats.hits) << " μsec/hit.";
21. Não escreva várias expressões em uma única linha.
22. Agrupe trechos de código dentro das funções e separe-os com no máximo uma linha em branco.
23. Separe funções, classes etc. com uma ou duas linhas em branco.
24. A const (relacionado a um valor) deve ser escrito antes do nome do tipo.
//correto
const char * pos
const std::string & s
//incorreto
char const * pos
25. Ao declarar um ponteiro ou uma referência, os símbolos * e & devem ser separados por espaços dos dois lados.
//correto
const char * pos
//incorreto
const char* pos
const char *pos
26. Ao usar tipos Template, crie aliases para eles com a palavra-chave using (exceto nos casos mais simples).
Em outras palavras, os parâmetros de Template são especificados apenas em using e não são repetidos no código.
using pode ser declarado localmente, por exemplo, dentro de uma função.
//correto
using FileStreams = std::map<std::string, std::shared_ptr<Stream>>;
FileStreams streams;
//incorreto
std::map<std::string, std::shared_ptr<Stream>> streams;
27. Não declare várias variáveis de tipos diferentes na mesma instrução.
28. Não use casts no estilo C.
//incorreto
std::cerr << (int)c <<; std::endl;
//correto
std::cerr << static_cast<int>(c) << std::endl;
29. Em classes e structs, agrupe membros e funções separadamente em cada escopo de visibilidade.
30. Para classes e structs pequenas, não é necessário separar a declaração do método da implementação.
O mesmo vale para métodos pequenos em quaisquer classes ou structs.
Para classes e structs template, não separe as declarações dos métodos da implementação (porque, caso contrário, elas terão de ser definidas na mesma unidade de tradução).
31. Você pode quebrar linhas em 140 caracteres, em vez de 80.
32. Sempre use os operadores de pré-incremento/pré-decremento se o pós-fixo não for necessário.
for (Names::const_iterator it = column_names.begin(); it != column_names.end(); ++it)
1. Certifique-se de adicionar comentários em todas as partes não triviais do código.
Isso é muito importante. Escrever o comentário pode ajudar você a perceber que o código não é necessário ou que foi mal projetado.
/** Part of piece of memory, that can be used.
* For example, if internal_buffer is 1MB, and there was only 10 bytes loaded to buffer from file for reading,
* then working_buffer will have size of only 10 bytes
* (working_buffer.end() will point to position right after those 10 bytes available for read).
*/
2. Os comentários podem ser tão detalhados quanto for necessário.
3. Coloque os comentários antes do código que eles descrevem. Em casos raros, os comentários podem vir depois do código, na mesma linha.
/** Analisa e executa a consulta.
*/
void executeQuery(
ReadBuffer & istr, /// De onde ler a consulta (e os dados para INSERT, se aplicável)
WriteBuffer & ostr, /// Onde escrever o resultado
Context & context, /// BD, tabelas, tipos de dados, motores, funções, funções de agregação...
BlockInputStreamPtr & query_plan, /// Aqui pode ser escrita a descrição de como a consulta foi executada
QueryProcessingStage::Enum stage = QueryProcessingStage::Complete /// Até qual estágio processar a consulta SELECT
)
4. Os comentários devem ser escritos apenas em inglês.
5. Se você estiver escrevendo uma biblioteca, inclua comentários detalhados explicando-a no arquivo de cabeçalho principal.
6. Não adicione comentários que não tragam informações adicionais. Em particular, não deixe comentários vazios como este:
/*
* Procedure Name:
* Original procedure name:
* Author:
* Date of creation:
* Dates of modification:
* Modification authors:
* Original file name:
* Purpose:
* Intent:
* Designation:
* Classes used:
* Constants:
* Local variables:
* Parameters:
* Date of creation:
* Purpose:
*/
O exemplo foi tirado de http://home.tamk.fi/~jaalto/course/coding-style/doc/unmaintainable-code/.
7. Não escreva comentários inúteis (autor, data de criação ..) no início de cada arquivo.
8. Comentários de uma linha começam com três barras: ///, e comentários de várias linhas começam com /**. Esses comentários são considerados “documentação”.
Observação: Você pode usar o Doxygen para gerar documentação a partir desses comentários. Mas, em geral, o Doxygen não é usado, porque é mais prático navegar pelo código na IDE.
9. Comentários de várias linhas não devem ter linhas em branco no início nem no fim (exceto a linha que fecha um comentário de várias linhas).
10. Para comentar trechos de código, use comentários básicos, não comentários de “documentação”.
11. Exclua as partes comentadas do código antes de fazer o commit.
12. Não use palavrões em comentários nem no código.
13. Não use letras maiúsculas. Não use pontuação em excesso.
14. Não use comentários como delimitadores.
///******************************************************
15. Não comece discussões nos comentários.
/// Why did you do this stuff?
16. Não é necessário escrever um comentário no final de um bloco explicando do que ele tratava.
1. Use letras minúsculas com sublinhados nos nomes de variáveis e membros da classe.
2. Para os nomes de funções (métodos), use camelCase iniciando com letra minúscula.
std::string getName() const override { return "Memory"; }
3. Para os nomes de classes (structs), use CamelCase começando com letra maiúscula. Não são usados prefixos diferentes de I para interfaces.
class StorageMemory : public IStorage
4. using recebem nomes da mesma forma que as classes.
5. Nomes de argumentos de tipo de template: em casos simples, use T; T, U; T1, T2.
Em casos mais complexos, siga as regras para nomes de classes ou adicione o prefixo T.
template <typename TKey, typename TValue>
struct AggregatedStatElement
6. Nomes dos argumentos constantes do template: devem seguir as regras para nomes de variáveis ou, em casos simples, usar N.
template <bool without_www>
struct ExtractDomain
7. Para classes abstratas (interfaces), você pode usar o prefixo I.
8. Se você usar uma variável apenas localmente, pode usar um nome curto.
Em todos os outros casos, use um nome que descreva seu significado.
bool info_successfully_loaded = false;
9. Os nomes de defines e constantes globais usam ALL_CAPS com underscores.
#define MAX_SRC_TABLE_NAMES_TO_STORE 1000
10. Os nomes dos arquivos devem seguir o mesmo padrão do seu conteúdo.
Se um arquivo contiver uma única classe, nomeie-o da mesma forma que a classe (CamelCase).
Se o arquivo contiver uma única função, nomeie-o da mesma forma que a função (camelCase).
11. Se o nome contiver uma abreviação, então:
- Para nomes de variáveis, a abreviação deve usar letras minúsculas:
mysql_connection (não mySQL_connection).
- Para nomes de classes e funções, mantenha as letras maiúsculas na abreviação:
MySQLConnection (não MySqlConnection).
12. Os argumentos do construtor usados apenas para inicializar os membros da classe devem ter o mesmo nome que os membros da classe, mas com um sublinhado no final.
FileQueueProcessor(
const std::string & path_,
const std::string & prefix_,
std::shared_ptr<FileHandler> handler_)
: path(path_),
prefix(prefix_),
handler(handler_),
log(&Logger::get("FileQueueProcessor"))
{
}
O sufixo com underscore pode ser omitido se o argumento não for usado no corpo do construtor.
13. Não há diferença entre os nomes de variáveis locais e os membros da classe (não é necessário usar prefixos).
14. Para as constantes de um enum, use CamelCase com inicial maiúscula. ALL_CAPS também é aceitável. Se o enum não for local, use uma enum class.
enum class CompressionMethod
{
QuickLZ = 0,
LZ4 = 1,
};
15. Todos os nomes devem estar em inglês. Não é permitida a transliteração de palavras em hebraico.
não T_PAAMAYIM_NEKUDOTAYIM
16. Abreviações são aceitáveis se forem bem conhecidas (quando for fácil encontrar o significado da abreviação na Wikipedia ou em um mecanismo de busca).
AST, SQL.
Não NVDH (algumas letras aleatórias)
Palavras incompletas são aceitáveis se a forma abreviada for de uso comum.
Você também pode usar uma abreviação se o nome completo estiver incluído ao lado dela nos comentários.
17. Nomes de arquivos com código-fonte em C++ devem ter a extensão .cpp. Arquivos de cabeçalho devem ter a extensão .h.
1. Gerenciamento de memória.
A desalocação manual de memória (delete) só pode ser usada em código de biblioteca.
Em código de biblioteca, o operador delete só pode ser usado em destrutores.
No código da aplicação, a memória deve ser liberada pelo objeto que é seu dono.
Exemplos:
- A forma mais fácil é colocar um objeto na stack ou torná-lo membro de outra classe.
- Para um grande número de objetos pequenos, use contêineres.
- Para a desalocação automática de um pequeno número de objetos que residem no heap, use
shared_ptr/unique_ptr.
2. Gerenciamento de recursos.
Use RAII e veja acima.
3. Tratamento de erros.
Use exceções. Na maioria dos casos, você só precisa lançar uma exceção e não precisa capturá-la (por causa de RAII).
Em aplicações de processamento de dados offline, muitas vezes é aceitável não capturar exceções.
Em servidores que tratam solicitações de usuários, geralmente basta capturar exceções no nível mais alto do handler de conexão.
Em funções de thread, você deve capturar e armazenar todas as exceções para relançá-las na thread principal após join.
/// Se ainda não houve nenhum cálculo, calcule o primeiro bloco de forma síncrona
if (!started)
{
calculate();
started = true;
}
else /// Se os cálculos já estão em andamento, aguarde o resultado
pool.wait();
if (exception)
exception->rethrow();
Nunca oculte exceções sem tratá-las. Nunca simplesmente registre todas as exceções no log sem critério.
//Incorreto
catch (...) {}
Se você precisar ignorar algumas exceções, faça isso apenas para casos específicos e relance as demais.
catch (const DB::Exception & e)
{
if (e.code() == ErrorCodes::UNKNOWN_AGGREGATE_FUNCTION)
return nullptr;
else
throw;
}
Ao usar funções com códigos de resposta ou errno, sempre verifique o resultado e lance uma exceção em caso de erro.
if (0 != close(fd))
throw ErrnoException(ErrorCodes::CANNOT_CLOSE_FILE, "Cannot close file {}", file_name);
Você pode usar assert para verificar invariantes no código.
4. Tipos de exceção.
Não é necessário usar uma hierarquia complexa de exceções no código da aplicação. O texto da exceção deve ser compreensível para um administrador de sistemas.
5. Lançar exceções em destrutores.
Isso não é recomendado, mas é permitido.
Use as seguintes opções:
- Crie uma função (
done() ou finalize()) que execute antecipadamente todo o trabalho que possa levar a uma exceção. Se essa função tiver sido chamada, não deverá haver exceções no destrutor depois.
- Tarefas muito complexas (como enviar mensagens pela rede) podem ser colocadas em um método separado que o usuário da classe terá de chamar antes da destruição.
- Se houver uma exceção no destrutor, é melhor registrá-la em log do que ocultá-la (se o logger estiver disponível).
- Em aplicações simples, é aceitável contar com
std::terminate (para casos de noexcept por padrão no C++11) para lidar com exceções.
6. Blocos de código anônimos.
Você pode criar um bloco de código separado dentro de uma única função para tornar determinadas variáveis locais, de modo que os destruidores sejam chamados ao sair do bloco.
Block block = data.in->read();
{
std::lock_guard<std::mutex> lock(mutex);
data.ready = true;
data.block = block;
}
ready_any.set();
7. Multithreading.
Em programas offline de processamento de dados:
- Tente obter o melhor desempenho possível em um único núcleo de CPU. Depois, você pode paralelizar o código, se necessário.
Em aplicações de servidor:
- Use o pool de threads para processar solicitações. Até o momento, não tivemos nenhuma tarefa que exigisse troca de contexto em userspace.
Fork não é usado para paralelização.
8. Sincronização de threads.
Muitas vezes, é possível fazer com que threads diferentes usem regiões de memória diferentes (melhor ainda: linhas de cache diferentes) e não usar nenhuma sincronização entre threads (exceto joinAll).
Se a sincronização for necessária, na maioria dos casos, basta usar um mutex com lock_guard.
Em outros casos, use primitivas de sincronização do sistema. Não use espera ocupada.
Operações atômicas devem ser usadas apenas nos casos mais simples.
Não tente implementar estruturas de dados lock-free, a menos que essa seja sua principal área de especialização.
9. Ponteiros vs referências.
Na maioria dos casos, prefira referências.
10. const.
Use referências constantes, ponteiros para constantes, const_iterator e métodos const.
Considere const como o padrão e use não const apenas quando necessário.
Ao passar variáveis por valor, usar const geralmente não faz sentido.
11. unsigned.
Use unsigned se necessário.
12. Tipos numéricos.
Use os tipos UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32 e Int64, bem como size_t, ssize_t e ptrdiff_t.
Não use estes tipos para números: signed/unsigned long, long long, short, signed/unsigned char, char.
13. Passagem de argumentos.
Passe valores complexos por valor se eles forem movidos e use std::move; passe por referência se quiser atualizar o valor em um loop.
Se uma função assumir a posse de um objeto criado no heap, defina o tipo do argumento como shared_ptr ou unique_ptr.
14. Valores de retorno.
Na maioria dos casos, basta usar return. Não escreva return std::move(res).
Se a função alocar um objeto no heap e retorná-lo, use shared_ptr ou unique_ptr.
Em casos raros (ao atualizar um valor em um loop), talvez seja necessário retornar o valor por meio de um argumento. Nesse caso, o argumento deve ser uma referência.
using AggregateFunctionPtr = std::shared_ptr<IAggregateFunction>;
/** Permite criar uma função de agregação pelo seu nome.
*/
class AggregateFunctionFactory
{
public:
AggregateFunctionFactory();
AggregateFunctionPtr get(const String & name, const DataTypes & argument_types) const;
15. namespace.
Não é necessário usar um namespace separado para o código da aplicação.
Bibliotecas pequenas também não precisam disso.
Para bibliotecas de médio a grande porte, coloque tudo em um namespace.
No arquivo .h da biblioteca, você pode usar namespace detail para ocultar detalhes de implementação desnecessários para o código da aplicação.
Em um arquivo .cpp, você pode usar static ou um namespace anônimo para ocultar símbolos.
Além disso, um namespace pode ser usado com um enum para evitar que os nomes correspondentes vazem para um namespace externo (mas é melhor usar enum class).
16. Inicialização adiada.
Se a inicialização exigir argumentos, normalmente você não deve escrever um construtor padrão.
Se mais tarde for preciso adiar a inicialização, você pode adicionar um construtor padrão que criará um objeto inválido. Ou, para um número pequeno de objetos, usar shared_ptr/unique_ptr.
Loader(DB::Connection * connection_, const std::string & query, size_t max_block_size_);
/// Para inicialização adiada
Loader() {}
17. Funções virtuais.
Se a classe não se destina ao uso polimórfico, não é necessário tornar as funções virtuais. Isso também se aplica ao destrutor.
18. Codificações.
Use UTF-8 em todos os lugares. Use std::string e char *. Não use std::wstring nem wchar_t.
19. Logging.
Veja os exemplos ao longo do código.
Antes de fazer commit, remova todo logging sem sentido e de depuração, bem como quaisquer outros tipos de saída de depuração.
O logging em loops deve ser evitado, mesmo no nível Trace.
Os logs devem ser legíveis em qualquer nível de log.
Em geral, o logging deve ser usado apenas no código da aplicação.
As mensagens de log devem ser escritas em inglês.
De preferência, o log deve ser compreensível para o administrador do sistema.
Não use palavrões no log.
Use codificação UTF-8 no log. Em casos raros, você pode usar caracteres não ASCII no log.
20. Entrada e saída.
Não use iostreams em loops internos críticos para o desempenho da aplicação (e nunca use stringstream).
Use a biblioteca DB/IO em vez disso.
21. Data e hora.
Veja a biblioteca DateLUT.
22. include.
Sempre use #pragma once em vez de guardas de inclusão.
23. using.
Não use using namespace. Você pode usar using para algo específico. Mas mantenha isso local dentro de uma classe ou função.
24. Não use trailing return type para funções, a menos que seja necessário.
25. Declaração e inicialização de variáveis.
//forma correta
std::string s = "Hello";
std::string s{"Hello"};
//forma incorreta
auto s = std::string{"Hello"};
26. Para funções virtuais, escreva virtual na classe base, mas use override em vez de virtual nas classes derivadas.
Funcionalidades não utilizadas do C++
1. Herança virtual não é usada.
2. Construções que ganharam açúcar sintático no C++ moderno, por exemplo.
// Forma tradicional sem açúcar sintático
template <typename G, typename = std::enable_if_t<std::is_same<G, F>::value, void>> // SFINAE via std::enable_if, uso de ::value
std::pair<int, int> func(const E<G> & e) // tipo de retorno especificado explicitamente
{
if (elements.count(e)) // teste de pertencimento .count()
{
// ...
}
elements.erase(
std::remove_if(
elements.begin(), elements.end(),
[&](const auto x){
return x == 1;
}),
elements.end()); // idioma remove-erase
return std::make_pair(1, 2); // cria par via make_pair()
}
// Com açúcar sintático (C++14/17/20)
template <typename G>
requires std::same_v<G, F> // SFINAE via conceito C++20, uso de alias de template C++14
auto func(const E<G> & e) // tipo de retorno auto (C++14)
{
if (elements.contains(e)) // teste de pertencimento .contains do C++20
{
// ...
}
elements.erase_if(
elements,
[&](const auto x){
return x == 1;
}); // std::erase_if do C++20
return {1, 2}; // ou: return std::pair(1, 2); // cria par via lista de inicialização ou inicialização por valor (C++17)
}
1. Escrevemos código para uma plataforma específica.
Mas, mantidas as demais condições, dá-se preferência a código multiplataforma ou portável.
2. Linguagem: C++20 (veja a lista de recursos disponíveis do C++20).
3. Compilador: clang. No momento em que este texto foi escrito (março de 2025), o código é compilado com clang versão >= 19.
A biblioteca padrão utilizada é a libc++.
4. SO: Ubuntu Linux, não anterior ao Precise.
5. O código é escrito para a arquitetura de CPU x86_64.
O conjunto de instruções da CPU é o conjunto mínimo compatível entre nossos servidores. Atualmente, é SSE 4.2.
6. Use as flags de compilação -Wall -Wextra -Werror -Weverything, com algumas exceções.
7. Use vinculação estática com todas as bibliotecas, exceto aquelas que são difíceis de vincular estaticamente (veja a saída do comando ldd).
8. O código é desenvolvido e depurado com configurações de release.
1. O KDevelop é uma boa IDE.
2. Para depuração, use gdb, valgrind (memcheck), strace, -fsanitize=... ou tcmalloc_minimal_debug.
3. Para análise de desempenho, use Linux Perf, valgrind (callgrind) ou strace -cf.
4. O código-fonte está no Git.
5. A compilação usa CMake.
6. Os programas são distribuídos em pacotes deb.
7. Commits na master não devem quebrar a compilação.
Embora apenas revisões selecionadas sejam consideradas funcionais.
8. Faça commits com a maior frequência possível, mesmo que o código esteja apenas parcialmente pronto.
Use branches para isso.
Se o seu código na branch master ainda não puder ser compilado, exclua-o da compilação antes do push. Você precisará finalizá-lo ou removê-lo em poucos dias.
9. Para alterações não triviais, use branches e publique-as no servidor.
10. Código não utilizado é removido do repositório.
1. A biblioteca padrão do C++20 é usada (extensões experimentais são permitidas), assim como os frameworks boost e Poco.
2. Não é permitido usar bibliotecas de pacotes do sistema operacional. Também não é permitido usar bibliotecas pré-instaladas. Todas as bibliotecas devem ser incluídas como código-fonte no diretório contrib e compiladas com o ClickHouse. Consulte Diretrizes para adicionar novas bibliotecas de terceiros para mais detalhes.
3. A preferência é sempre por bibliotecas que já estão em uso.
1. Escreva o mínimo de código possível.
2. Tente a solução mais simples.
3. Não escreva código até saber como ele vai funcionar e como o laço interno vai operar.
4. Nos casos mais simples, use using em vez de classes ou structs.
5. Se possível, não implemente construtores de cópia, operadores de atribuição, destrutores (exceto um virtual, se a classe contiver pelo menos uma função virtual), construtores de movimento nem operadores de atribuição por movimento. Em outras palavras, as funções geradas pelo compilador devem funcionar corretamente. Você pode usar default.
6. A simplificação do código é incentivada. Reduza o tamanho do código sempre que possível.
1. Especificar explicitamente std:: para tipos de stddef.h
não é recomendável. Em outras palavras, recomendamos escrever size_t em vez de std::size_t, porque é mais curto.
É aceitável adicionar std::.
2. Especificar explicitamente std:: para funções da biblioteca padrão de C
não é recomendável. Em outras palavras, escreva memcpy em vez de std::memcpy.
O motivo é que existem funções não padrão semelhantes, como memmem. Nós as usamos ocasionalmente. Essas funções não existem no namespace std.
Se você escrever std::memcpy em vez de memcpy em todos os lugares, memmem sem std:: vai parecer estranho.
Ainda assim, você pode usar std:: se preferir.
3. Usar funções de C quando as mesmas estiverem disponíveis na biblioteca padrão de C++.
Isso é aceitável se for mais eficiente.
Por exemplo, use memcpy em vez de std::copy para copiar grandes blocos de memória.
4. Argumentos de função em várias linhas.
Qualquer um dos estilos de quebra de linha a seguir é permitido:
function(
size_t left, size_t right,
const & RangesInDataParts ranges,
size_t limit)
function(size_t left, size_t right,
const & RangesInDataParts ranges,
size_t limit)
function(size_t left, size_t right,
const & RangesInDataParts ranges,
size_t limit)
function(
size_t left,
size_t right,
const & RangesInDataParts ranges,
size_t limit)
Última modificação em 10 de junho de 2026