erro: passar xxx como argumento 'this' de xxx descarta qualificadores


457
#include <iostream>
#include <set>

using namespace std;

class StudentT {

public:
    int id;
    string name;
public:
    StudentT(int _id, string _name) : id(_id), name(_name) {
    }
    int getId() {
        return id;
    }
    string getName() {
        return name;
    }
};

inline bool operator< (StudentT s1, StudentT s2) {
    return  s1.getId() < s2.getId();
}

int main() {

    set<StudentT> st;
    StudentT s1(0, "Tom");
    StudentT s2(1, "Tim");
    st.insert(s1);
    st.insert(s2);
    set<StudentT> :: iterator itr;
    for (itr = st.begin(); itr != st.end(); itr++) {
        cout << itr->getId() << " " << itr->getName() << endl;
    }
    return 0;
}

Na linha:

cout << itr->getId() << " " << itr->getName() << endl;

Dá um erro que:

../main.cpp:35: erro: passar 'const StudentT' como 'this' argumento de 'int StudentT :: getId ()' descarta qualificadores

../main.cpp:35: erro: passar 'const StudentT' como 'this' argumento de 'std :: string StudentT :: getName ()' descarta qualificadores

O que há de errado com este código? Obrigado!


13
Onde está a linha 35 no seu snippet de código?
In silico

118
Desejo GCC iria melhorar esta mensagem de erro, por exemplo, "descarta qualificadores" -> "breaks const correção"
jfritz42

13
@ jfritz42: seria confuso para o caso, descartavolatile
PlasmaHH

3
@PlasmaHH, a mensagem de erro seria dividida em "quebra a correção da const" e "quebra a correção da volátil". Agora, muitas pessoas não pensam em algo volátil correto
#

Respostas:


524

Os objetos no std::setsão armazenados como const StudentT. Portanto, quando você tenta chamar getId()o constobjeto, o compilador detecta um problema, principalmente você está chamando uma função de membro não-const no objeto const, o que não é permitido porque as funções de membro que não fazem const NÃO prometem não modificar o objeto; portanto, o compilador fará uma suposição segura que getId()pode tentar modificar o objeto, mas, ao mesmo tempo, também nota que o objeto é const; portanto, qualquer tentativa de modificar o objeto const deve ser um erro. Portanto, o compilador gera uma mensagem de erro.

A solução é simples: torne as funções constantes como:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Isso é necessário porque agora você pode chamar getId()e getName()const objetos como:

void f(const StudentT & s)
{
     cout << s.getId();   //now okay, but error with your versions
     cout << s.getName(); //now okay, but error with your versions
}

Como nota de rodapé, você deve implementar operator<como:

inline bool operator< (const StudentT & s1, const StudentT & s2)
{
    return  s1.getId() < s2.getId();
}

Os parâmetros de nota agora são constreferência.


3
Uma explicação tão clara. Obrigado. Mas eu me pergunto sobre o seu último trecho de código. Por que usar referência no parâmetro de função? const StudentT & s1, const StudentT & s2?
Rafael Adel

2
@RafaelAdel: Você usa referência para evitar cópias desnecessárias e, constcomo a função não precisa modificar o objeto, a aplicação é constimposta no momento da compilação.
precisa

90

As funções de membro que não modificam a instância da classe devem ser declaradas como const:

int getId() const {
    return id;
}
string getName() const {
    return name;
}

Sempre que você vê "descarta qualificadores", está falando sobre constou volatile.


2
@ Fr - Você acha que é definitivamente um requisito adicionar modificadores const às funções de membros que não modificam a instância da classe? Existe alguma outra razão para o erro neste caso? Duvido, porque na maioria dos getters que escrevo, não adiciono modificadores const a ele.
Mahesh

@ Mahesh: Sim, faz parte da correção constante . Não sei ao certo de onde constestá vindo, mas suspeito que setesteja retornando uma referência const do iterador para impedir que a instância seja alterada e, assim, invalidar o conjunto.
Fred Larson

@ Mahesh: Não passaria na minha revisão de código. Eu tenho um colega de trabalho que se refere a mim como o "constante". 8v) Mude isso foo obj;para const foo obj;uma vez e veja o que acontece. Ou passe uma constreferência para a foo.
Fred Larson

3
@Mahesh: É como eu disse - se os elementos em um setforem alterados, a ordem poderá ser alterada e o conjunto não será mais válido. Em a map, apenas a chave é const. Em a set, todo o objeto é realmente a chave.
Fred Larson

1
@Mahesh: const são necessários, caso contrário você não pode chamá-los com objetos const. veja a função f()na minha resposta.
Nawaz

5

Na verdade, o padrão C ++ (ou seja, rascunho C ++ 0x ) diz (tnx para @Xeo e @Ben Voigt por apontar isso para mim):

23.2.4 Contêineres associativos
5 Para definir e multiset, o tipo de valor é igual ao tipo de chave. Para mapa e multimapa, é igual ao par. As chaves em um contêiner associativo são imutáveis.
O iterador 6 de um contêiner associativo é da categoria de iterador bidirecional. Para contêineres associativos em que o tipo de valor é igual ao tipo de chave, o iterador e o const_iterator são iteradores constantes. Não é especificado se o iterador e o const_iterator são ou não do mesmo tipo.

Portanto, a implementação do VC ++ 2008 Dinkumware está com defeito.


Resposta antiga:

Você recebeu esse erro porque em certas implementações da lib std set::iteratoré o mesmo que set::const_iterator.

Por exemplo, o libstdc ++ (fornecido com o g ++) possui (veja aqui o código-fonte inteiro):

typedef typename _Rep_type::const_iterator            iterator;
typedef typename _Rep_type::const_iterator            const_iterator;

E nos documentos da SGI , afirma:

iterator       Container  Iterator used to iterate through a set.
const_iterator Container  Const iterator used to iterate through a set. (Iterator and const_iterator are the same type.)

Por outro lado, o VC ++ 2008 Express compila seu código sem reclamar que você está chamando métodos não const em set::iterators.


2

Vamos dar um exemplo mais detalhado. Quanto à estrutura abaixo:

struct Count{
    uint32_t c;

    Count(uint32_t i=0):c(i){}

    uint32_t getCount(){
        return c;
    }

    uint32_t add(const Count& count){
        uint32_t total = c + count.getCount();
        return total;
    }
};

insira a descrição da imagem aqui

Como você vê acima, o IDE (CLion), dará dicas Non-const function 'getCount' is called on the const object. No método add counté declarado como objeto const, mas o método getCountnão é const, portanto, count.getCount()pode alterar os membros emcount .

Erro de compilação como abaixo (mensagem principal no meu compilador):

error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]

Para resolver o problema acima, você pode:

  1. mude o método uint32_t getCount(){...}para uint32_t getCount() const {...}. Então count.getCount()não vai mudar os membros count.

ou

  1. mude uint32_t add(const Count& count){...}para uint32_t add(Count& count){...}. Portanto count, não se importe em mudar de membro.

Quanto ao seu problema, os objetos no std :: set são armazenados como const StudentT, mas o método getIdegetName não são const, portanto, você fornece o erro acima.

Você também pode ver esta pergunta Significado de 'const' por último em uma declaração de função de uma classe? para mais detalhes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.