Até onde você vai const
? Você apenas faz funções const
quando necessário, ou usa todo o porco e as usa em todos os lugares? Por exemplo, imagine um mutador simples que use um único parâmetro booleano:
void SetValue(const bool b) { my_val_ = b; }
Isso é const
realmente útil? Pessoalmente, opto por usá-lo extensivamente, incluindo parâmetros, mas, neste caso, gostaria de saber se vale a pena?
Também fiquei surpreso ao saber que você pode omitir const
dos parâmetros em uma declaração de função, mas pode incluí-lo na definição da função, por exemplo:
arquivo .h
void func(int n, long l);
arquivo .cpp
void func(const int n, const long l)
Existe uma razão para isso? Parece um pouco incomum para mim.
Respostas:
O motivo é que const para o parâmetro se aplica apenas localmente na função, pois está trabalhando em uma cópia dos dados. Isso significa que a assinatura da função é realmente a mesma de qualquer maneira. Provavelmente é um estilo ruim fazer muito isso.
Pessoalmente, tendem a não usar const, exceto para parâmetros de referência e ponteiro. Para objetos copiados, isso realmente não importa, embora possa ser mais seguro, pois sinaliza a intenção dentro da função. É realmente uma decisão judicial. No entanto, costumo usar const_iterator ao fazer um loop em algo e não pretendo modificá-lo, então acho que cada um é seu, desde que a correção const para tipos de referência seja rigorosamente mantida.
fonte
const
retirada dos protótipos de função tem a vantagem de que você não precisa alterar o arquivo de cabeçalho se decidir abandonar aconst
parte da implementação posteriormente.const
onde isso faz uma diferença útil".const
sempre que possível; é mais expressivo. Quando li código de outra pessoa, eu uso pequenos indicadores como este para julgar quanto cuidado eles colocaram em escrever seu código ao lado de coisas como números de magia, comentando, e uso ponteiro adequado, etc.int getDouble(int a){ ++a; return 2*a; }
Tente isso. Obviamente,++a
ele não tem nada a ver, mas pode ser encontrado em uma função longa, escrita por mais de um programador por um longo período de tempo. Eu sugiro fortemente escreverint getDouble( const int a ){ //... }
que irá gerar um erro de compilação ao encontrar++a;
.class Foo { int multiply(int a, int b) const; }
no seu cabeçalho. Na sua implementação, você se importa em prometer não alterara
e,b
portanto,int Foo::multiply(const int a, const int b) const { }
faz sentido aqui. (Sidenote: o chamador e os cuidados de implementação sobre o fato de que a função não altera seuFoo
objeto, assim a const no final da sua declaração)"const não faz sentido quando o argumento é passado por valor, pois você não modificará o objeto do chamador."
Errado.
Trata-se de documentar seu código e suas suposições.
Se seu código tem muitas pessoas trabalhando nele e suas funções não são triviais, você deve marcar "const" todo e qualquer um que puder. Ao escrever um código de força industrial, você sempre deve presumir que seus colegas de trabalho são psicopatas, tentando fazer com que você o faça da maneira que puderem (especialmente porque geralmente é você mesmo no futuro).
Além disso, como alguém mencionado anteriormente, pode ajudar o compilador a otimizar um pouco as coisas (embora seja um tiro no escuro).
fonte
Às vezes (com muita frequência!) Eu tenho que desembaraçar o código C ++ de outra pessoa. E todos sabemos que o código C ++ de outra pessoa é uma bagunça completa quase por definição :) Portanto, a primeira coisa que faço para decifrar o fluxo de dados local é colocar const em todas as definições de variáveis até o compilador começar a latir. Isso significa argumentos de valor de qualificação constante também, porque são apenas variáveis locais sofisticadas inicializadas pelo chamador.
Ah, eu gostaria que as variáveis fossem const por padrão e mutável fosse necessário para variáveis não const :)
fonte
[x](){return ++x;}
é um erro; veja aquiconst
" por padrão em Rust :)As duas linhas a seguir são funcionalmente equivalentes:
Obviamente, você não poderá modificar
a
no corpofoo
se ele for definido da segunda maneira, mas não há diferença do lado de fora.Onde
const
realmente é útil é com parâmetros de referência ou ponteiro:O que isso diz é que foo pode receber um parâmetro grande, talvez uma estrutura de dados de tamanho em gigabytes, sem copiá-lo. Além disso, ele diz ao chamador: "Foo não * altera o conteúdo desse parâmetro". Passar uma referência const também permite que o compilador tome certas decisões de desempenho.
*: A menos que elimine a constância, mas isso é outro post.
fonte
Const extra supérflua é ruim do ponto de vista da API:
Colocar constantes supérfluas extras em seu código para parâmetros intrínsecos passados por valor atrapalha sua API, sem fazer nenhuma promessa significativa ao chamador ou usuário da API (apenas prejudica a implementação).
Excesso de 'const' em uma API quando não é necessário é como " lobo chorando "; eventualmente, as pessoas começarão a ignorar 'const' porque está em todo lugar e não significa nada na maioria das vezes.
O argumento "reductio ad absurdum" para considerações extras na API é bom, pois esses dois primeiros pontos seriam: se mais parâmetros const forem bons, todos os argumentos que possam ter uma const, devem ter uma const. De fato, se fosse realmente tão bom, você desejaria que const seja o padrão para parâmetros e tenha uma palavra-chave como "mutável" somente quando desejar alterar o parâmetro.
Então, vamos tentar colocar const sempre que possível:
Considere a linha de código acima. A declaração não é apenas mais confusa, longa e difícil de ler, mas três das quatro palavras-chave 'const' podem ser ignoradas com segurança pelo usuário da API. No entanto, o uso extra de 'const' tornou a segunda linha potencialmente PERIGOSA!
Por quê?
Uma rápida leitura incorreta do primeiro parâmetro
char * const buffer
pode fazer você pensar que ele não modificará a memória no buffer de dados que é passado - no entanto, isso não é verdade! 'Const' supérfluo pode levar a suposições perigosas e incorretas sobre sua API quando digitalizadas ou mal interpretadas rapidamente.Const supérfluo também é ruim do ponto de vista de implementação de código:
Se FLEXIBLE_IMPLEMENTATION não for verdadeiro, a API é "promissora" para não implementar a função da primeira maneira abaixo.
Essa é uma promessa muito boba de se fazer. Por que você deve fazer uma promessa que não oferece benefício algum ao seu interlocutor e limita apenas sua implementação?
Ambas são implementações perfeitamente válidas da mesma função; portanto, tudo o que você fez foi amarrar uma mão pelas costas desnecessariamente.
Além disso, é uma promessa muito superficial que é fácil (e contornada legalmente).
Olha, eu implementei dessa maneira de qualquer maneira, apesar de prometer não fazê-lo - apenas usando uma função de wrapper. É como quando o bandido promete não matar alguém em um filme e ordena que seu capanga o mate.
Essas constantes supérfluas não valem mais do que a promessa de um bandido de cinema.
Mas a capacidade de mentir fica ainda pior:
Fui informado de que você pode incompatível const no cabeçalho (declaração) e código (definição) usando const espúria. Os advogados const-happy afirmam que isso é uma coisa boa, pois permite que você coloque const apenas na definição.
No entanto, o inverso é verdadeiro ... você pode colocar uma const espúria apenas na declaração e ignorá-la na definição. Isso torna a const supérflua em uma API apenas uma coisa terrível e uma mentira horrível - veja este exemplo:
Tudo o que a const supérflua realmente faz é tornar o código do implementador menos legível, forçando-o a usar outra cópia local ou uma função de wrapper quando ele deseja alterar a variável ou passar a variável por referência não const.
Veja este exemplo. Qual é mais legível? É óbvio que a única razão para a variável extra na segunda função é porque algum designer de API lançou uma const supérflua?
Espero que tenhamos aprendido algo aqui. Const supérfluo é um desagradável desordem da API, uma chatice irritante, uma promessa superficial e sem sentido, um obstáculo desnecessário e, ocasionalmente, leva a erros muito perigosos.
fonte
void foo(int)
evoid foo(const int)
tem exatamente a mesma função, não sobrecargas. ideone.com/npN4W4 ideone.com/tZav9R A const aqui é apenas um detalhe de implementação do corpo da função e não afeta a resolução de sobrecarga. Deixe o const fora da declaração, para uma API mais segura e organizada, mas coloque const na definição , se você não quiser modificar o valor copiado.pi++
quando não deveriam.const deveria ter sido o padrão em C ++. Como isso :
fonte
unsigned
deveria ter sido o padrão em C ++. Assim:int i = 5; // i is unsigned
esigned int i = 5; // i is signed
.Quando codifiquei C ++ como meio de vida, constituí tudo o que pude. Usar const é uma ótima maneira de ajudar o compilador a ajudá-lo. Por exemplo, manter os valores de retorno do método pode salvá-lo de erros de digitação, como:
quando você quis dizer:
Se foo () estiver definido para retornar uma referência não const:
O compilador permitirá que você atribua um valor ao temporário anônimo retornado pela chamada de função. Fazendo const:
Elimina essa possibilidade.
fonte
foo() = 42
: error: lvalue exigido como operando à esquerda de cessãoconst int foo()
é de um tipo diferenteint foo()
, o que cria grandes problemas se você estiver usando indicadores de função, sistemas de sinal / slot ou boost :: bind.const int& foo()
efetivamente o mesmo queint foo()
, devido à otimização do valor de retorno?Há uma boa discussão sobre esse tópico nos antigos artigos "Guru da semana" sobre comp.lang.c ++. Moderados aqui .
O artigo correspondente do GOTW está disponível no site da Herb Sutter aqui .
fonte
Eu digo const seus parâmetros de valor.
Considere esta função de buggy:
Se o parâmetro number fosse const, o compilador pararia e nos alertaria sobre o bug.
fonte
Eu uso const on parâmetros de função que são referências (ou ponteiros) que são apenas [no] dados e não serão modificados pela função. Ou seja, quando o objetivo de usar uma referência é evitar a cópia de dados e não permitir a alteração do parâmetro passado.
Colocar const no parâmetro booleano b no seu exemplo coloca apenas uma restrição na implementação e não contribui para a interface da classe (embora geralmente não seja recomendável alterar parâmetros).
A assinatura da função para
e
é o mesmo, o que explica seus .c e .h
Asaf
fonte
Se você usa os operadores
->*
ou.*
, é uma obrigação.Impede que você escreva algo como
o que eu quase fiz agora e que provavelmente não faz o que você pretende.
O que eu pretendia dizer era
e se eu tivesse colocado um
const
entreBar *
ep
, o compilador teria me dito isso.fonte
Ah, uma pergunta difícil. Por um lado, uma declaração é um contrato e realmente não faz sentido passar um argumento const por valor. Por outro lado, se você observar a implementação da função, poderá oferecer ao compilador mais chances de otimizar se declarar um argumento constante.
fonte
const não faz sentido quando o argumento é passado por valor, pois você não modificará o objeto do chamador.
const deve ser preferido ao passar por referência, a menos que o objetivo da função seja modificar o valor passado.
Finalmente, uma função que não modifica o objeto atual (isto) pode e provavelmente deve ser declarada const. Um exemplo está abaixo:
Esta é uma promessa de não modificar o objeto ao qual esta chamada é aplicada. Em outras palavras, você pode ligar para:
Se a função não fosse const, isso resultaria em um aviso do compilador.
fonte
A marcação de parâmetros de valor 'const' é definitivamente uma coisa subjetiva.
No entanto, na verdade, prefiro marcar os parâmetros de valor const, como no seu exemplo.
O valor para mim indica claramente que os valores dos parâmetros da função nunca são alterados pela função. Eles terão o mesmo valor no início e no final. Para mim, é parte de manter um estilo de programação muito funcional.
Para uma função curta, é indiscutivelmente um desperdício de tempo / espaço ter o 'const' lá, já que geralmente é bastante óbvio que os argumentos não são modificados pela função.
No entanto, para uma função maior, é uma forma de documentação de implementação e é imposta pelo compilador.
Posso ter certeza de que, se fizer algum cálculo com 'n' e 'l', posso refatorar / mover esse cálculo sem medo de obter um resultado diferente porque perdi um lugar onde um ou ambos foram alterados.
Como é um detalhe de implementação, você não precisa declarar os parâmetros de valor const no cabeçalho, assim como não precisa declarar os parâmetros de função com os mesmos nomes que a implementação usa.
fonte
Pode ser que esse argumento não seja válido. mas se incrementarmos o valor de uma variável const dentro de um compilador de funções, ocorrerá um erro: " erro: incremento do parâmetro somente leitura ". então isso significa que podemos usar a palavra-chave const como uma maneira de impedir a modificação acidental de nossas variáveis dentro de funções (que não devemos / somente leitura). por isso, se o fizermos acidentalmente no compilador, informaremos isso. isso é especialmente importante se você não é o único que está trabalhando neste projeto.
fonte
Eu costumo usar const sempre que possível. (Ou outra palavra-chave apropriada para o idioma de destino.) Faço isso puramente porque permite que o compilador faça otimizações extras que não seriam capazes de fazer de outra maneira. Como não tenho idéia de quais podem ser essas otimizações, sempre o faço, mesmo quando parece bobagem.
Pelo que sei, o compilador pode muito bem ver um parâmetro de valor const e dizer: "Ei, essa função não está modificando isso de qualquer maneira, para que eu possa passar por referência e salvar alguns ciclos de relógio". Eu acho que nunca faria isso, uma vez que altera a assinatura da função, mas isso é verdade. Talvez ele faça alguma manipulação de pilha diferente ou algo assim ... O ponto é, eu não sei, mas sei que tentar ser mais inteligente do que o compilador só me leva a ser envergonhado.
O C ++ possui uma bagagem extra, com a ideia de correção constante, tornando-se ainda mais importante.
fonte
const
. Em vez disso, é uma questão de declarar a intenção na implementação e capturar pensamentos mais tarde (incrementar acidentalmente a variável local errada, porque não eraconst
). Paralelamente, também acrescentaria que os compiladores são muito bem-vindos para alterar as assinaturas de funções, no sentido de que as funções podem ser incorporadas e, uma vez destacadas, toda a maneira como elas funcionam pode ser alterada; adicionar ou remover referências, fazer literais de 'variáveis', etc, estão todos dentro da regra como se1. Melhor resposta com base na minha avaliação:
A resposta de @Adisak é a melhor resposta aqui, com base na minha avaliação. Observe que essa resposta é, em parte, a melhor porque também é a mais bem-suportada com exemplos de códigos reais , além de usar som e lógica bem pensada.
2. Minhas próprias palavras (concordando com a melhor resposta):
const
. Tudo o que faz é:const
qualquer lugar pode impedir isso.const
desnecessariamente desorganiza o código comconst
s em todos os lugares, afastando a atenção dosconst
que são realmente necessários para ter um código seguro.const
é extremamente importante quando necessário e deve ser usado, pois evita efeitos colaterais indesejados com alterações persistentes fora da função e, portanto, cada ponteiro ou referência deve ser usadoconst
quando o parm é apenas uma entrada, não é uma saída. Usarconst
apenas os parâmetros passados por referência ou ponteiro tem o benefício adicional de tornar realmente óbvio quais parâmetros são ponteiros ou referências. É mais uma coisa a se destacar e dizer "Cuidado! Qualquer parâmetro aoconst
lado é uma referência ou ponteiro!".3) Palavras do Google (concordando comigo e a melhor resposta):
(No " Guia de estilo do Google C ++ ")
Fonte: a seção "Uso de const" do Guia de Estilo do Google C ++: https://google.github.io/styleguide/cppguide.html#Use_of_const . Esta é realmente uma seção realmente valiosa, então leia a seção inteira.
Observe que "TotW # 109" significa "Dica da semana # 109:
const
declarações significativas de função" e também é uma leitura útil. É mais informativo e menos prescritivo sobre o que fazer e com base no contexto anterior à regra do Google C ++ Style Guide sobreconst
citada acima, mas como resultado da clareza fornecida, aconst
regra citada acima foi adicionada ao Google C ++ Guia de estilo.Observe também que, embora eu esteja citando o Guia de estilo do Google C ++ aqui em defesa da minha posição, isso NÃO significa que eu sempre sigo o guia ou sempre o recomendo. Algumas das coisas que eles recomendam são simplesmente estranhas, como a
kDaysInAWeek
convenção de nomenclatura ao estilo de "Nomes Constantes" . No entanto, ainda é útil e relevante apontar quando uma das empresas técnicas e de software mais influentes e bem-sucedidas do mundo usa a mesma justificativa que eu e outras pessoas como a @Adisak para apoiar nossos pontos de vista sobre esse assunto.4. O linter de Clang,,
clang-tidy
tem algumas opções para isso:A. É importante notar também que linter de Clang,
clang-tidy
, tem uma opção,readability-avoid-const-params-in-decls
, descrito aqui , para apoiar a aplicação em uma base de código não usandoconst
para parâmetros de função passagem por valor :E aqui estão mais dois exemplos que estou me acrescentando por completude e clareza:
B. Ele também possui esta opção:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html5. Minha abordagem pragmática de como redigir um guia de estilo sobre o assunto:
Eu simplesmente copio e colo isso no meu guia de estilo:
[INÍCIO DE COPIAR / COLAR]
const
nos parâmetros de função passados por referência ou ponteiro quando seu conteúdo (para o que eles apontam) NÃO for alterado. Dessa forma, torna-se óbvio quando se espera que uma variável passada por referência ou ponteiro seja alterada, porque ela faltaráconst
. Nesse caso de usoconst
evita efeitos colaterais acidentais fora da função.const
parâmetros de função passados por valor, porqueconst
não afeta o chamador: mesmo que a variável seja alterada na função, não haverá efeitos colaterais fora da função. Consulte os seguintes recursos para obter justificativa e insight adicionais:const
nas declarações de funções"const
[isto é,const
em parâmetros passados por valor ] em parâmetros de função em declarações que não são definições (e tenha cuidado para não copiar / colar um significadoconst
). Ele não faz sentido e é ignorado pelo compilador, é ruído visual. , e pode enganar os leitores "( https://abseil.io/tips/109 , grifo do autor).const
qualificadores que afetam a compilação são aqueles colocados na definição da função, NÃO aqueles em uma declaração direta da função, como em uma declaração da função (método) em um arquivo de cabeçalho.const
[ie:const
em variáveis passadas por valor ] em valores retornados por uma função.const
de ponteiros ou referências retornados por uma função depende do implementador , pois às vezes é útil.clang-tidy
opções acima com as seguintes opções:Aqui estão alguns exemplos de código para demonstrar as
const
regras descritas acima:const
Exemplos de parâmetros:(alguns são emprestados daqui )
const
Exemplos de tipos de retorno:(alguns são emprestados daqui )
[FIM DE COPIAR / COLAR]
fonte
No caso mencionado, isso não afeta os chamadores da sua API, e é por isso que isso não é feito com frequência (e não é necessário no cabeçalho). Isso afeta apenas a implementação da sua função.
Não é uma coisa particularmente ruim de se fazer, mas os benefícios não são tão bons, pois não afetam sua API e adicionam digitação, por isso geralmente não é feito.
fonte
Eu não uso const para parametere com valor passado. O chamador não se importa se você modifica o parâmetro ou não, é um detalhe de implementação.
O que é realmente importante é marcar os métodos como const se eles não modificarem sua instância. Faça isso à medida que avança, porque, caso contrário, você poderá acabar com muitas const_cast <> ou poderá achar que marcar uma const de método requer alterar muito código, pois chama outros métodos que deveriam ter sido marcados como const.
Eu também tendem a marcar const Vars local, se eu não precisar modificá-los. Eu acredito que facilita a compreensão do código, facilitando a identificação das "partes móveis".
fonte
Sobre otimizações do compilador: http://www.gotw.ca/gotw/081.htm
fonte
Eu uso const onde posso. Const para parâmetros significa que eles não devem alterar seu valor. Isso é especialmente valioso ao passar por referência. const for function declara que a função não deve alterar os membros das classes.
fonte
Para resumir:
std::vector::at(size_type pos)
. O que é bom o suficiente para a biblioteca padrão é bom para mim.fonte
_Tmp
o tempo todo - você não deseja isso (na verdade, não tem permissão para usá-los).Se o parâmetro é passado por valor (e não é uma referência), geralmente não há muita diferença se o parâmetro é declarado como const ou não (a menos que contenha um membro de referência - não é um problema para os tipos internos). Se o parâmetro é uma referência ou ponteiro, geralmente é melhor proteger a memória referenciada / apontada para ele, não o ponteiro propriamente dito (acho que você não pode tornar a referência em si constante, não que isso importe tanto quanto você não pode mudar o árbitro) . Parece uma boa ideia proteger tudo o que puder como const. Você pode omiti-lo sem medo de cometer um erro se os parâmetros forem apenas PODs (incluindo tipos internos) e não houver chance deles mudarem mais ao longo da estrada (por exemplo, no seu exemplo, o parâmetro bool).
Eu não sabia sobre a diferença de declaração de arquivo .h / .cpp, mas faz algum sentido. No nível do código da máquina, nada é "const"; portanto, se você declarar uma função (no .h) como não-const, o código será o mesmo que se você a declarar como const (otimizações à parte). No entanto, ajuda a recrutar o compilador para que você não altere o valor da variável na implementação da função (.ccp). Pode ser útil no caso em que você está herdando de uma interface que permite alterações, mas não precisa alterar o parâmetro para obter a funcionalidade necessária.
fonte
Eu não colocaria const em parâmetros assim - todo mundo já sabe que um booleano (ao contrário de um booleano &) é constante; portanto, adicioná-lo fará com que as pessoas pensem "espere, o que?" ou mesmo que você esteja passando o parâmetro por referência.
fonte
o que devemos lembrar com const é que é muito mais fácil tornar as coisas constantes desde o início, do que tentar colocá-las mais tarde.
Use const quando quiser que algo permaneça inalterado - é uma dica adicional que descreve o que sua função faz e o que esperar. Eu já vi muitas APIs C que poderiam fazer com algumas delas, especialmente aquelas que aceitam c-strings!
Eu estaria mais inclinado a omitir a palavra-chave const no arquivo cpp do que no cabeçalho, mas como eu costumo recortar e colá-las, elas serão mantidas nos dois lugares. Não tenho idéia do por que o compilador permite isso, acho que é uma coisa do compilador. A melhor prática é definitivamente colocar sua palavra-chave const nos dois arquivos.
fonte
Não há realmente nenhuma razão para criar um parâmetro de valor "const", pois a função só pode modificar uma cópia da variável.
O motivo para usar "const" é se você está passando algo maior (por exemplo, uma estrutura com muitos membros) por referência; nesse caso, garante que a função não possa modificá-lo; ou melhor, o compilador reclamará se você tentar modificá-lo da maneira convencional. Impede que seja acidentalmente modificado.
fonte
O parâmetro Const é útil apenas quando o parâmetro é passado por referência, ou seja, referência ou ponteiro. Quando o compilador vê um parâmetro const, certifique-se de que a variável usada no parâmetro não seja modificada no corpo da função. Por que alguém iria querer tornar um parâmetro por valor tão constante? :-)
fonte
const
declara claramente: 'Não preciso modificar isso, por isso estou declarando isso. Se eu tentar modificá-lo mais tarde, me dê um erro em tempo de compilação para que eu possa corrigir meu erro ou desmarcar comoconst
'. Portanto, é uma questão de higiene e segurança do código. Por tudo o que é necessário adicionar aos arquivos de implementação, deve ser algo que as pessoas fazem como um reflexo puro, IMO.Como os parâmetros estão sendo passados por valor, isso não faz diferença se você especificar const ou não da perspectiva da função de chamada. Basicamente, não faz sentido declarar os parâmetros de passagem por valor como const.
fonte
Todas as vantagens em seus exemplos não têm propósito. C ++ é passado por valor por padrão, portanto, a função obtém cópias dessas entradas e booleanos. Mesmo que a função os modifique, a cópia do chamador não é afetada.
Então, eu evitaria consts extras porque
fonte
Eu sei que a pergunta está "um pouco" desatualizada, mas como eu vim através dela, outra pessoa também poderá fazê-lo no futuro ... ... ainda assim, duvido que o pobre sujeito esteja listado aqui para ler meu comentário :)
Parece-me que ainda estamos confinados à maneira de pensar no estilo C. No paradigma OOP, brincamos com objetos, não com tipos. O objeto Const pode ser conceitualmente diferente de um objeto não-const, especificamente no sentido de const-lógico (em contraste com const-a bit a bit). Assim, mesmo que a correção constante dos parâmetros de função seja (talvez) um excesso de cuidado no caso de PODs, não é assim no caso de objetos. Se uma função trabalha com um objeto const, deve-se dizer isso. Considere o seguinte snippet de código
ps .: você pode argumentar que a referência (const) seria mais apropriada aqui e oferece o mesmo comportamento. Bem, certo. Apenas dando uma imagem diferente do que eu podia ver em outro lugar ...
fonte