Explicação do uso de C ++ Const

97
const int* const Method3(const int* const&) const;

Alguém pode explicar o uso de cada um dos constantes?

RoR
fonte
27
Eu realmente gosto deste método para decifrar declarações complicadas: c-faq.com/decl/spiral.anderson.html
Jason,

Respostas:

77

Leia isto: https://isocpp.org/wiki/faq/const-correctness

O final constsignifica que a funçãoMethod3 não modifica os membros não mutáveis ​​de sua classe.

const int* constsignifica um ponteiro constante para um int constante: ou seja, um ponteiro que não pode ser alterado, para um int que não pode ser alterado: a única diferença entre isso e const int&é que pode sernull

const int* const&significa uma referência a um ponteiro constante para um int constante. Normalmente, os ponteiros não são passados ​​por referência; const int* &faz mais sentido porque significaria que o ponteiro poderia ser alterado durante a chamada do método, que seria a única razão que vejo para passar um ponteiro por referência, const int* const&é para todas as intenções e finalidades iguais, const int* constexceto que é provavelmente menos eficiente como ponteiros são tipos de dados antigos simples (POD) e devem, em geral, ser passados ​​por valor.

satnhak
fonte
103

É mais fácil de entender se você reescrever isso como o equivalente completamente

// v───v───v───v───v───v───v───v───v───v───v───v─┬┐
//                                               ││
//  v──#1    v─#2             v──#3    v─#4      #5
   int const * const Method3(int const * const&) const;

em seguida, leia da direita para a esquerda.

# 5 diz que toda a declaração de função à esquerda é const, o que implica que esta é necessariamente uma função-membro em vez de uma função livre.

# 4 diz que o ponteiro à esquerda é const(não pode ser alterado para apontar para um endereço diferente).

# 3 diz que o intà esquerda é const(não pode ser alterado para ter um valor diferente).

# 2 diz que o ponteiro à esquerda é const.

# 1 diz que intà esquerda éconst .

Juntando tudo isso, você pode ler isso como uma constfunção de membro chamada Method3que faz referência a um constponteiro para um int const(ou a const int, se preferir) e retorna um constponteiro para um int const( const int).

(Nb # 2 é totalmente supérfluo .)

ildjarn
fonte
22

Em primeiro lugar, const Té equivalente a T const.

const int* consté portanto equivalente a int const * const.

Ao ler expressões com muitos consttokens e ponteiros, sempre tente lê-los da direita para a esquerda (após aplicar a transformação acima). Portanto, neste caso, o valor de retorno é um ponteiro const para um constint . Fazer o próprio ponteiro não constfaz sentido aqui, pois o valor de retorno não é um lvalue que pode ser modificado. Fazer a ponta const, entretanto, garante que o chamador não pode modificar o int(ou array de ints) retornado por Method3.

const int*const&torna-se int const*const&, portanto, é uma referência a um ponteiro const para um constint . Passar um ponteiro const por referências masculinas também não faz sentido - você não pode modificar o valor referenciado já que o ponteiro é conste as referências e ponteiros ocupam armazenamento igual, então não há nenhuma economia de espaço também.

O último constindica que o método não modifica o thisobjeto. O thisponteiro dentro do corpo do método terá a declaração (teórica) T const * const this. Isso significa que um const T*objeto será capaz de chamar T::Method3().

Alexander Gessler
fonte
2
Votando isso (e a resposta semelhante de ildjarn), em parte por deixar claro que a coisa toda faz mais sentido se você não colocar o primeiro consts no início da frase. É precisamente por isso que acho uma má prática colocar constlá, embora a linguagem o permita, e é o uso mais comum.
TED de
12

Uma maneira fácil de lembrar as regras do consté pensar da seguinte maneira: constaplica-se à coisa à sua esquerda, a menos que não haja nada à sua esquerda.

Portanto, no caso de const int * const, a primeira const não tem nada à sua esquerda, então ela se aplica a inte a segunda tem algo à sua esquerda, então ela se aplica ao ponteiro.

Esta regra também informa o que aconteceria no caso de você ter const int const *. Uma vez que ambos os constantes se aplicam a intesta expressão, é redundante e, portanto, inválido.

Yony
fonte
3
const /* don't modify the int or array of ints' value(s) */
int* const /* as a retval, ignored. useless declaration */
Method3(const /* don't modify the int or array of ints' value(s) */
int* const /* don't modify the pointer's value, the address to which `pointer` points to. e.g. you cannot say `++pointer` */
&) const; /* this method does not modify the instance/object which implements the method */
justin
fonte
3

Eu gosto de usar o método "relógio" ou "espiral" onde, começando com o nome do identificador (neste caso Method3), você lê da esquerda para a direita e vice-versa, etc. para decodificar convenções de nomenclatura. Portanto, const int* const Method3(const int* const&) consté um método de classe que não altera nenhum membro da classe (de alguma classe sem nome) e faz uma referência constante a um ponteiro que aponta para uma constante inte retorna um ponteiro constante para uma constante int.

Espero que isto ajude,

Jason

Jason
fonte
2

Uma maneira fácil de lembrar o const em C ++ é quando você vê algum código na forma de:

XXX const;
const YYY;

XXX, YYY será um componente constante,
XXX constforma:

function ( def var ) const;    ------#1
* const;                       ------#2

const YYY Formato:

const int;                     ------#3
const double;

As pessoas costumam usar esses tipos. Quando você vir em "const&"algum lugar, não se sinta confuso, const está descrevendo algo antes de si mesmo. portanto, a resposta a esse problema é evidente agora.

const int* const Method3(const int* const&) const;
  |          |             |          |       |
  #3         #2            #3         #2      #1
Albert Chen
fonte
2

Eu só quero mencionar que const int* const&é de fato uma referência constante a const int*. Por exemplo:

int i = 0;
int j = 1;
int* p = &i;
int* q = &j;
const int* const& cpref = p;
cpref = q; //Error: assignment of read-only reference 'cpref'

É também o caso de int* const&, O que significa: "Uma referência constante a int*".
Mas const int*&é uma referência não constante a const int*.
Espero que isto ajude.

MrDetective
fonte
1

Ler da direita para a esquerda facilita a compreensão dos modificadores.

Um método const que faz referência a um ponteiro const para um const int chamado Method3que retorna um ponteiro const para um const int.

  1. Um método const não pode modificar membros (a menos que sejam criteriosamente mutable)
  2. Um ponteiro const não pode ser alterado para apontar para outra coisa
  3. Um const int (ou qualquer outro tipo) não pode ser modificado
Nick Strupat
fonte
1

const # 1: O ponteiro retornado por Method3 se refere a um const int.

const # 2: O valor do ponteiro retornado pela própria função é const. Esta é uma const inútil (embora gramaticalmente válida), porque o valor de retorno de uma função não pode ser um valor l.

const # 3: O tipo de ponteiro passado por referência à função aponta para um const int.

const # 4: O valor do ponteiro passado por referência à função é, ele mesmo, um ponteiro const. Declarar um valor que é passado para uma função como const normalmente seria inútil, mas esse valor é passado por referência, portanto, pode ser significativo.

const # 5: A função (presumivelmente uma função-membro) é const, o que significa que não é permitido (a) atribuir novos valores a qualquer membro do objeto do qual faz parte ou (b) chamar uma função-membro não const sobre o objeto ou qualquer um de seus membros.

Jollymorphic
fonte
0
  • const no final do método está o qualificador, significando que o estado do objeto não será alterado.

  • const int*const&significa receber por referência um ponteiro const para uma localização const. Ele não pode mudar para apontar para um local diferente, nem mudar o valor para o qual está apontando.

  • const int*const é o valor de retorno que também é um ponteiro constante para um local constante.

Mahesh
fonte
0

Alguns exemplos podem ser bons para demonstrar esse conceito, quanto mais, melhor imho.

class TestClass
{
private:
   int iValue;
   int* oValuePtr;
   int& oValueRef;

public:
   int TestClass::ByValMethod1(int Value)
   {
      // Value can be modified
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   int TestClass::ByValMethod2(const int Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod3(int Value)
   {
      // Value can be modified
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod4(const int Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue can be modified
      iValue = Value;
      iValue += 1;

      // Return value can be modified
      return ++iValue;
   }

   const int TestClass::ByValMethod5(const int Value) const
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // iValue *cannot* be modified
      // Access through a const object
      iValue = Value;
      iValue += 1;

      // Return value *cannot* be modified
      // Access through a const object
      return ++iValue;
   }

   int& TestClass::ByRefMethod1(int& Value)
   {
      // Value can be modified
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   int& TestClass::ByRefMethod2(const int& Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod3(int& Value)
   {
      // Value can be modified
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod4(const int& Value)
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   const int& TestClass::ByRefMethod5(const int& Value) const
   {
      // Value *cannot* be modified
      // Variable is const variable
      Value++;

      // oValueRef can be modified
      oValueRef = Value;
      oValueRef += 1;

      // Return value can be modified
      return ++oValueRef;
   }

   int* TestClass::PointerMethod1(int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr can be assigned
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   int* TestClass::PointerMethod2(const int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr cannot be assigned
      // const int* to int*
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod3(int* Value)
   {
      // Value can be modified
      Value++;

      // oValuePtr can be assigned
      oValuePtr = Value;

      // iValue can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod4(const int* Value)
   {
      // Value cannot be modified
      Value++;

      // oValuePtr *cannot* be assigned
      // const int* to int*
      oValuePtr = Value;

      // oValuePtr can be modified
      oValuePtr += 1;

      // Return value can be modified
      return ++oValuePtr;
   }

   const int* TestClass::PointerMethod5(const int* Value) const
   {
      // Value can be modified
      ++Value;

      // oValuePtr *cannot* be assigned
      // const int* to int* const
      // Access through a const object
      oValuePtr = Value;

      // oValuePtr *cannot* be modified
      // Access through a const object
      oValuePtr += 1;

      // Return value *cannot* be modified
      return ++oValuePtr;
   }
};

Eu espero que isso ajude!

Rastus7
fonte