| FAQ Lite | ||||||||||||||||||||||||||
| Precisão const | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void f1(const String& s); // Pass by reference-to-const
void f2(const String* sptr); // Pass by pointer-to-const
void f3(String s); // Pass by value
| Nos casos Pass by reference-to-const e Pass by pointer-to-const, qualquer tentativa de alterar o String do chamador dentro da
função f() será flagrada pelo compilador como um erro em tempo de
compilação. Essa verificação é feita inteiramente em tempo de compilação: não
causa qualquer aumento de tamanho do programa ou perda de performance em tempo de
execução. No caso Pass by
value, a funçào chamada obtem uma cópia do String do chamador.
Isso significa que f3() pode alterar sua cópia local, mas a cópia será destruida quando f3() retornar. Em
particular, f3() não podem alterar o objeto String do chamador. Um exemplo contrário. Se você quer criar uma função g() que aceita um String, mas você quer que os que chamam g() saibam que g() poderá alterar o objeto String do chamador. Nesse caso você pode ter g() recebendo seu parâmetro String ... |
void g1(String& s); // Pass by reference-to-non-const
void g2(String* sptr); // Pass by pointer-to-non-const
| A ausência de const nessas funções diz ao compilador que elas tem permissão, embora não sejam obrigadas a isso, para alterar o objeto String do chamador. Assim, os chamadores podem passar o seu parâmetro String para qualquer das funções f(), mas apenas f3() (a que recebe parâmetros by value) pode passar seu String para g1() ou para g2(). Se f1() ou f2() precisam chamar qualquer das funções g(), uma cópia local do objeto String deve ser passada para a função g(); o parâmetro recebido por f1() ou por f2() não pode ser passado diretamente para qualquer das funções g(). Por exemplo: |
void g1(String& s);
void f1(const String& s)
{
g1(s); // Compile-time Error since s is const
String localCopy = s;
g1(localCopy); // OK since localCopy is not const
}
| Naturalmente, no caso acima, qualquer alteração que g1()fizer, será feita no objeto localCopy que é local para f1(). Em particular, nenhuma alteração será feita no parâmetro const que foi passado para f1() |
| [18.2] Como precisão const se relaciona com segurança de tipos de dados normais? |
| Declarar a constância de um parâmetro é apenas uma outra forma de dar segurança
de tipos de dados. Pode-se dizer que uma const String, por exemplo, é de uma
classe diferente de um String comum, já que a variante const está impedindo qualquer operação
de modificação que podem ser realizadas com a variante não-const. Por exemplo,
você pode imaginar que uma const
String simplesmente não tem um operador de atribuição
de conteúdo. Se você já acha que a segurança de tipos comuns o ajuda a implementar um sistema correto (e isso é verdade, especialmente em grandes sistemas), você achará que proteção de const também o ajuda. |
| [18.3] Devo proteger os itens com const tão logo seja possível, ou mais tarde? |
| No início, o mais cedo que for possível. Pendências para corriigir os itens para const pode se tornar uma bola de neve: cada const que você adiciona aqui, requer que você adicione quantro outras ali e lá |
| [18.4] O que significa const Fred* p ? |
| Significa que
p aponta para um objeto da classe Fred, mas p não pode ser usado
para alterar aquele objeto Fred (naturalmente, p poderia também ser NULL) Por exemplo, se a classe Fred tem uma função membro const denominada inspect(), dizer p->inspect() está certo. Mas se a classe Fred tem uma função membro não-const denominada mutate(), dizer p->mutate() é um erro (o erro é pego pelo compilador, nenhum teste é feito em tempo de execução, o que significa que const não diminui a performance de seu programa) |
| [18.5] Qual é a diferença
entre const Fred* p, Fred*
const p e const Fred* const p ? |
Você deve ler as declarações de pointer da direita para a
esquerda.
|
| [18.6] O que significa const Fred& x ? |
| Significa "x é um alias de Fred, mas x não pode ser usado
para alterar o objeto Fred. Por exemplo, se a classe Fred tem uma função membro const denominada inspect(), dizer x.inspect() é Ok. Mas se a classe Fred tem uma função membro não-const denominada mutate(), dizer x.mutate() é um erro (o erro é pego pelo compilador, nenhum teste é feito em tempo de execução, o que significa que usar proteção de const não reduz a velocidade de execução de seu programa). |
| [18.7] Fred& const x faz algum sentido? |
| Não. Não não faz qualquer sentido. Para descobrir o que a declaração acima significa, você deve lê-la da direita para a esquerda. Assim, Fred& const x significa "x é uma referência const para Fred". Mas essa declaração é redundante, já que referências são sempre const. Você não pode alterar o conteúdo de uma referência. Nunca. Com ou sem a especificação const explícita. Em outras palavras, Fred& const x é funcionalmente equivalente a Fred& x. Já que você não melhora seu código em nada por acrescentar const após &, você não deve acrescentá-la para não confundir as pessoas que vão ler o seu código. Ou seja, o termo const vai fazer algumas pessoas pensarem que Fred é uma const, como se você tivesse escrito "const Fred& x" |
| [18.8] O que significa Fred const& x ? |
| Fred const& x é funcionalmente equivalente a const Fred& x. O problema com o uso de Fred const& x (com o const antes de &) é que essa forma pode ser digitada erradamente como Fred &const x, que é uma declaração sem sentido. Melhor e mais simples usar const Fred& x. |
| [18.9] O que é uma função membro const ? |
| Uma função membro que inspeciona, ao invés de modificar, seu
objeto. Uma função membro const é indicada pelo sufixo const imediatamente após sua lista de parâmetros. Funções membro com um sufixo const são denominadas funções membros const ou inspetoras. Funções membro sem um sufixo const são denominadas funções membro não-const ou modificadoras. |
class Fred {
public:
void inspect() const; // This member promises NOT to change *this
void mutate(); // This member function might change *this
};
void userCode(Fred& changeable, const Fred& unchangeable)
{
changeable.inspect(); // OK: doesn't change a changeable object
changeable.mutate(); // OK: changes a changeable object
unchangeable.inspect(); // OK: doesn't change an unchangeable object
unchangeable.mutate(); // ERROR: attempt to change unchangeable object
}
void f(const int* p1, int* p2)
{
int i = *p1; // Get the (original) value of *p1
*p2 = 7; // If p1 == p2, this will also change *p1
int j = *p1; // Get the (possibly new) value of *p1
if (i != j) {
cout << "*p1 changed, but it didn't change via pointer p1!\n";
assert(p1 == p2); // This is the only way *p1 could be different
}
}
main()
{
int x;
f(&x, &x); // This is perfectly legal (and even moral!)
}
| Note que main() e f(const int* int) poderiam estar em diferentes unidades de compilação, que foram compiladas em diferentes dias da semana. Nesse casos não há como o compilador detectar a existência de alias em tempo de compilação. Portanto não há como se definir uma regra de linguagem que proíba esse tipo de coisa. De fato, não é desejável que exista tal regra, uma vez que em geral se considera um recurso da linguagem a possibilidade de se ter vários pointers apontando para a mesma coisa. O fato de um dos pointer prometer não alterar a coisa apontada, é uma promessa feita pelo pointer e não em nome da coisa que ele aponta. |
| [18.13 ] const Fred* p significa que *p não pode ser alterado? |
| Não! Para melhor entendimento, leia a FAQ
anterior. const Fred* p significa que Fred não pode ser alterado via pointer p, mas qualquer outro pointer alias que não seja const pode ser usado para alterar o objeto Fred. Por exemplo, se você tem dois pointers const Fred* p e Fred* q que apontam para o mesmo objeto Fred, pointer q pode ser usado para alterar o objeto Fred, embora o pointer p não o possa. |
class Fred {
public:
void inspect() const; // A const member function
void mutate(); // A non-const member function
};
main()
{
Fred f;
const Fred* p = &f;
Fred* q = &f;
p->inspect(); // OK: No change to *p
p->mutate(); // Error: Can't change *p via p
q->inspect(); // OK: q is allowed to inspect the object
q->mutate(); // OK: q is allowed to mutate the object
}
|
| | Home | Bookmarks | Universidades | Para Saber mais | Universidades | WEB Directory | Mapa do site | | |