错误:将xxx作为xxx的“ this”参数传递会丢弃限定符


456
#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;
}

排队:

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

它给出一个错误:

../main.cpp:35:错误:将'const StudentT'传递为'int StudentT :: getId()'的'this'参数时,将丢弃限定符

../main.cpp:35:错误:将“ const StudentT”作为“ std :: string StudentT :: getName()”的“ this”参数传递

此代码有什么问题?谢谢!


13
您的代码段中的第35行在哪里?
2011年

117
我希望GCC可以改善此错误消息,例如“丢弃限定符”->“破坏常量正确性”
jfritz42

13
@ jfritz42:对于它丢弃的情况会感到困惑volatile
PlasmaHH 2013年

3
@PlasmaHH错误消息将被分为“破坏常量正确性”和“破坏易失性正确性”。现在,没有多少人会想到一些不稳定的正确信息
Caleth,2017年

Answers:


523

中的对象std::set存储为const StudentT。因此,当您尝试getId()使用该const对象进行调用时,编译器会检测到问题,主要是您在const对象上调用了一个非const成员函数,这是不允许的,因为非const成员函数使NO PROMISE不修改该对象;因此,编译器将做出一个安全的假设,getId()可能会尝试修改该对象,但与此同时,它还会注意到该对象是const;因此,任何试图修改const对象的尝试都应该是一个错误。因此,编译器会生成错误消息。

解决方案很简单:使函数const为:

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

这是必需的,因为现在您可以按以下方式调用const对象getId()getName()对其进行调用:

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
}

作为旁注,您应实现operator<为:

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

注意参数现在是const参考。


3
这样清晰的解释。谢谢。但我想知道您的最后一个代码片段。为什么在功能参数中使用引用?const StudentT & s1, const StudentT & s2
拉斐尔·阿德尔

2
@RafaelAdel:您可以使用引用来避免不必要的复制,并且const由于该函数不需要修改对象,因此const在编译时强制执行此操作。
Nawaz

90

不修改类实例的成员函数应声明为const

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

每当您看到“舍弃限定词”时,它就是在谈论constvolatile


2
@Fred-您认为绝对必须向不修改类实例的成员函数添加const修饰符吗?在这种情况下是否还有其他原因导致错误?我对此表示怀疑,因为在我编写的大多数吸气剂中,我没有向其添加const修饰符。
Mahesh

@Mahesh:是的,这是const正确性的一部分。我不确定哪里const来自哪里,但是我怀疑那个set正在从迭代器返回const引用,以防止实例发生更改从而使集合无效。
弗雷德·拉尔森

@Mahesh:无法通过我的代码审查。我有一个同事称我为“ const-able”。8v)将其更改foo obj;const foo obj;一次,然后看看会发生什么。或传递对的const引用foo
弗雷德·拉尔森

3
@Mahesh:就像我说的-如果a set中的元素被更改,则顺序可能会被打乱,然后该设置将不再有效。在中map,只有键是const。在中set,整个对象实际上是关键。
弗雷德·拉尔森

1
@Mahesh:const是必需的,否则您不能使用const对象调用它们。看到f()我的答案功能。
纳瓦兹

5

实际上,C ++标准(即C ++ 0x草稿)说(向@Xeo和@Ben Voigt发送tnx,以向我指出这一点):

23.2.4关联容器
5对于集合和多集,值类型与键类型相同。对于地图和多地图,它等于配对。关联容器中的键是不可变的。关联容器的
6迭代器属于双向迭代器类别。对于值类型与键类型相同的关联容器,iterator和const_iterator均为常量迭代器。不确定iterator和const_iterator是否为同一类型。

因此,VC ++ 2008 Dinkumware的实现是错误的。


旧答案:

之所以会出现此错误,是因为在std lib的某些实现中,set::iterator它与相同set::const_iterator

例如libstdc ++(与g ++一起提供)拥有它(有关完整源代码,请参见此处):

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

并且在SGI的文档中指出:

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.)

另一方面,VC ++ 2008 Express可以编译代码,而不会抱怨您在set::iterators 上调用了非const方法。


2

让我给一个更详细的例子。关于以下结构:

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;
    }
};

在此处输入图片说明

如您所见,IDE(CLion)将给出提示Non-const function 'getCount' is called on the const object。在方法add count中声明为const对象,但该方法getCount不是const方法,因此count.getCount()可能会更改成员count

编译错误如下(我的编译器中的核心消息):

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

要解决以上问题,您可以:

  1. 将方法更改uint32_t getCount(){...}uint32_t getCount() const {...}。因此,count.getCount()请勿更改中的成员count

要么

  1. 更改uint32_t add(const Count& count){...}uint32_t add(Count& count){...}。因此,count不必在意更改其中的成员。

至于你的问题,反对在的std ::集存储为const StudentT,但该方法getIdgetName没有const的,所以你给上述错误。

您还可以在一个类的函数声明中看到这个问题,“ const”的含义是什么?有关更多详细信息。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.