[C++] Introdução detalhada ao conhecimento básico (2)

Índice

1. Funções embutidas

1. Conceito

2. Características

3. Vantagens e desvantagens de funções e macros inline

2. A palavra-chave auto (C++11)

  1. Introdução ao automóvel

  2. As regras de uso do auto

    2.1 Auto é usado em combinação com ponteiros e referências

    2.2 Definir várias variáveis ​​na mesma linha

  3. Cenários onde o auto não pode ser derivado

    3.1 auto não pode ser usado como parâmetro de função

    3.2 auto não pode ser usado diretamente para declarar arrays

3. For loop baseado em intervalo (C++11)

  1. A sintaxe do intervalo para

  2. Condições para o uso de escopo para

    2.1 O intervalo de iterações do loop for deve ser definido

Quarto, o valor nulo do ponteiro nullptr (C++11)

  1. O valor nulo do ponteiro em C++98


1. Funções embutidas

1. Conceito

Uma função decorada com inline é chamada de função inline . Ao compilar, o compilador C++ a expandirá no local onde a função inline é chamada . Não há sobrecarga na criação de um quadro de pilha para chamadas de função. As funções inline melhoram a eficiência do programa operação .

Se você adicionar a palavra-chave embutida antes da função acima para transformá-la em uma função embutida, o compilador substituirá a chamada da função pelo corpo da função durante a compilação. Visto por:

1. No modo release, verifique se a chamada Add existe no código assembly gerado pelo compilador;

2. No modo de depuração, o compilador precisa ser definido, caso contrário, não será expandido (porque no modo de depuração, o compilador não otimizará o código por padrão, o método de configuração de vs2013 é fornecido abaixo)

2. Características

  1. Inline é um método de troca de espaço por tempo . Se o compilador tratar a função como uma função inline, ele substituirá a chamada da função pelo corpo da função durante a fase de compilação . Defeito: pode tornar o arquivo objeto maior. Vantagem: menos chamada sobrecarga, melhorar a eficiência da operação do programa.
  2. inline é apenas uma sugestão para o compilador. Diferentes compiladores podem ter diferentes mecanismos de implementação inline. A sugestão geral é: tornar a função menor (ou seja, a função não é muito longa, não há declaração exata, depende da implementação interna do compilador), nenhuma função recursiva e frequentemente chamada deve ser decorada com inline, caso contrário, o compilador irá ignorar o recurso inline.
  3. O Inline não recomenda a separação de declaração e definição, o que levará a erros de link . Como o inline é expandido, não há endereço de função e o link não será encontrado.

3. Vantagens e desvantagens de funções e macros inline

  A diferença entre funções inline e macros é que as macros são substituídas pelo pré-processador, enquanto as funções inline são implementadas por meio do controle do compilador, as macros são substituídas no estágio de pré-processamento e as funções inline são expandidas no estágio de compilação. Além disso, a função inline é uma função real, mas quando é necessária, a função inline é expandida como uma macro, de modo que o push dos parâmetros da função é cancelado e a sobrecarga da chamada é reduzida. Assim, você pode chamar funções inline como chamar funções sem se preocupar com problemas como macros.

  Na linguagem C, o uso de macros (#define) para escrever funções será otimizado, sem o consumo de stack frames, e é adequado para chamadas frequentes de pequenas funções . Mas as macros são um tanto defeituosas. Em C++, funções embutidas, constantes modificadas por const e enums são usados ​​em vez de macros.

Como substituir macros em C++:

  1. A definição de constante é substituída por const e enum.
  2. Em vez disso, definições curtas de função usam funções embutidas.

Prós e contras de funções inline?

vantagem:

  1. Como a função inline é uma função, os parâmetros da função têm tipos, portanto, a detecção do tipo de parâmetro será realizada durante o estágio de compilação, o que é mais seguro;
  2. A função inline foi expandida na fase de compilação, o que reduz a chamada de função e melhora a eficiência operacional da função;
  3. As funções inline não precisam adicionar parênteses em todos os lugares, como funções de macro, o que facilita a implementação;
  4. No modo Debug, ele não será expandido por padrão, você pode depurar ou verificar se está expandido configurando o compilador;
  5. Não haverá efeitos colaterais.

deficiência:

  1. Quase todos os locais onde uma função inline é usada serão expandidos, causando inchaço no código.

Prós e contras de macros?

(1) Vantagens e desvantagens das macro constantes

vantagem:

  1. Uma mudança e todas as mudanças para reduzir a probabilidade de erros e melhorar a legibilidade do código.

deficiência:

  1. A substituição é executada no nó de pré-processamento, nenhuma detecção de tipo é executada e a segurança do código é baixa.

(2) Vantagens e desvantagens das funções macro

vantagem:

  1. Não é uma função, o que reduz a sobrecarga de chamadas de função e melhora a eficiência operacional do programa;
  2. Pode salvar alguns códigos, porque a função de macro pode encapsular várias instruções;
  3. Pode melhorar a legibilidade do código.

deficiência:

  1. O estágio de pré-processamento da função macro é substituído, nenhuma detecção de tipo é executada e a segurança do código é baixa;
  2. As funções de macro não podem ser depuradas (porque são substituídas no estágio de pré-compilação);
  3. Sujeito a erros, cada parte da função macro precisa estar entre parênteses;
  4. A posição de cada função macro será expandida, o que causará expansão do código;
  5. As funções de macro podem ter efeitos colaterais.

2. A palavra-chave auto (C++11)

  1. Introdução ao automóvel

O significado de auto no início do C/C++ é: a variável modificada com auto é uma variável local com memória automática , mas infelizmente ninguém a tem usado. Em C++11, o comitê padrão deu a auto um novo significado: auto não é mais um indicador de tipo de armazenamento, mas um novo indicador de tipo para instruir o compilador, e a variável declarada por auto deve ser compilada pelo compilador derivado de período de tempo.

int TeTestAuto()
{
	return 10;
}
int main()
{
	int a = 10;
	auto b = a;//此时编译器会根据 a 的类型来对 b 的类型进行推导为 int
	auto c = 'a';
	auto d = TeTestAuto();
    auto e = &a;

	cout << typeid(b).name() << endl;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
    cout << typeid(e).name() << endl;
    return 0;
}

 typeid(nome da variável).name() pode imprimir o tipo de variável.

Nota: Ao usar auto para definir uma variável, ela deve ser inicializada.Na fase de compilação, o compilador precisa deduzir o tipo real de auto de acordo com a expressão de inicialização. Portanto, auto não é uma declaração de "tipo", mas um "placeholder" quando o tipo é declarado.O compilador substituirá auto pelo tipo real da variável durante a compilação.

  2. As regras de uso do auto

    2.1 Auto é usado em combinação com ponteiros e referências

Ao usar auto para declarar um tipo de ponteiro, não há diferença entre usar auto e auto*, mas ao usar auto para declarar um tipo de referência, você deve adicionar & .

int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;

cout << typeid(a).name() << endl;
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;

    2.2 Definir várias variáveis ​​na mesma linha

Ao declarar várias variáveis ​​na mesma linha, essas variáveis ​​devem ser do mesmo tipo , caso contrário, o compilador relatará um erro, porque o compilador na verdade apenas deduz o primeiro tipo e, em seguida, define outras variáveis ​​com o tipo deduzido.

void TestAuto()
{
    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

  3. Cenários onde o auto não pode ser derivado

    3.1 auto não pode ser usado como parâmetro de função

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
void TestAuto(auto a)
{}

    3.2 auto não pode ser usado diretamente para declarar arrays

void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {4,5,6}; //编译会失败
}

  Existem dois outros cenários: (1) Para evitar confusão com auto em C++98, C++11 apenas retém o uso de auto como um indicador de tipo; (2) a vantagem mais comum de auto na prática. O uso é usá-lo em conjunto com o novo loop for fornecido pelo C++11, que será mencionado posteriormente, assim como as expressões lambda.

3. For loop baseado em intervalo (C++11)

  1. A sintaxe do intervalo para

Os parênteses após o loop for são divididos em duas partes pelos dois pontos ":": a primeira parte é a variável usada para iteração no intervalo e a segunda parte representa o intervalo a ser iterado. Nesse caso, não há necessidade de especificar o escopo do loop ao percorrer toda a coleção.

void Test()
{
    int arr[] = { 1, 2, 3, 4, 5 };
    for (auto& e : arr)//要改变数组的值,需要使用引用
        e *= 2;

    for (auto e : arr)
        cout << e << " ";
}

  2. Condições para o uso de escopo para

    2.1 O intervalo de iterações do loop for deve ser definido

Para uma matriz, é o intervalo do primeiro elemento e do último elemento na matriz ; para uma classe, os métodos de início e fim devem ser fornecidos, e início e fim são o intervalo das iterações do loop for.

void TestFor(int array[])
{
    for(auto& e : array)
        cout<< e <<endl;
}

 Nota: Há um problema com o código acima, porque o escopo de for é incerto.

Quarto, o valor nulo do ponteiro nullptr (C++11)

  1. O valor nulo do ponteiro em C++98

NULL pode ser definido como a constante literal 0 ou como a constante de um ponteiro sem tipo (void*). Não importa que tipo de definição seja adotada, alguns problemas inevitavelmente serão encontrados ao usar ponteiros de valores nulos.

void f(int)
{
	cout << "f(int)" << endl;
}
void f(int*)
{
	cout << "f(int*)" << endl;
}
//这里函数重载,但结果都是f(int)
//C++中,NULL被定义为0,这也不知道为什么是个错误不太好
int main()
{
	f(0);
	f(NULL);
	return 0;
}

   A intenção original do programa é chamar a versão do ponteiro da função f(int*) por meio de f(NULL), mas como NULL é definido como 0, isso é contrário à intenção original do programa.

   Em C++98, a constante literal 0 pode ser um número inteiro ou uma constante de ponteiro sem tipo (void*), mas o compilador a trata como uma constante inteira por padrão. modo de ponteiro, ele deve ser forçado para (void *)0.

   Portanto, um patch foi feito em C++11 para substituir NULL por nullptr.

Perceber:

  1. O arquivo de cabeçalho não precisa ser incluído ao usar nullptr para representar o valor nulo do ponteiro, pois nullptr foi introduzido como uma nova palavra-chave em C++11.
  2. Em C++11, sizeof(nullptr) e sizeof((void*)0) ocupam o mesmo número de bytes.
  3. Para melhorar a robustez do código, é recomendável usar nullptr ao representar o valor nulo do ponteiro posteriormente.


Se houver deficiências neste artigo, sinta-se à vontade para comentar abaixo e corrigirei o mais rápido possível.

 Ferros velhos, lembre-se de curtir e prestar atenção!!!   

Acho que você gosta

Origin blog.csdn.net/m0_63198468/article/details/131218106
Recomendado
Clasificación