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

Posted

技术标签:

【中文标题】错误:将 xxx 作为 xxx 的“this”参数传递会丢弃限定符【英文标题】:error: passing xxx as 'this' argument of xxx discards qualifiers 【发布时间】:2011-08-23 19:48:06 【问题描述】:
#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' 参数传递会丢弃限定符

这段代码有什么问题?谢谢!

【问题讨论】:

代码 sn-p 中的第 35 行在哪里? 我希望 GCC 能改进这个错误信息,例如“丢弃限定符”->“破坏 const 正确性” @jfritz42:对于它丢弃 volatile 的情况会令人困惑 @PlasmaHH 错误消息将分为“破坏 const 正确性”和“破坏 volatile 正确性”。现在,没有多少人会考虑 volatile 正确 【参考方案1】:

std::set 中的对象存储为const StudentT。因此,当您尝试使用 const 对象调用 getId() 时,编译器会检测到问题,主要是您在 const 对象上调用非常量成员函数,这是不允许的,因为非常量成员函数不承诺不会修改对象;所以编译器会做出一个安全的假设,即getId() 可能会尝试修改该对象,但同时它也注意到该对象是常量;所以任何修改 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&lt; 实现为:

inline bool operator< (const StudentT & s1, const StudentT & s2)

    return  s1.getId() < s2.getId();

注意参数现在是const 参考。

【讨论】:

这么清晰的解释。谢谢。但我想知道你的最后一个代码 sn-p。为什么在函数参数中使用引用? const StudentT &amp; s1, const StudentT &amp; s2 ? @RafaelAdel:您使用引用来避免不必要的复制,const 因为函数不需要修改对象,所以const 在编译时强制执行此操作。【参考方案2】:

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

int getId() const 
    return id;

string getName() const 
    return name;

每当您看到“丢弃限定符”时,它指的是constvolatile

【讨论】:

@Fred - 你认为绝对需要向不修改类实例的成员函数添加 const 修饰符吗?在这种情况下,错误还有其他原因吗?我对此表示怀疑,因为在我编写的大多数 getter 中,我都没有添加 const 修饰符。 @Mahesh:是的,它是const correctness 的一部分。我不确定const 是从哪里来的,但我怀疑set 正在从迭代器返回一个常量引用,以防止实例更改从而使集合无效。 @Mahesh:不会通过我的代码审查。我有一位同事称我为“能干的人”。 8v) 将foo obj; 更改为const foo obj; 一次,看看会发生什么。或者将const 引用传递给foo @Mahesh:就像我说的那样——如果set 中的元素发生更改,则顺序可能会被打乱,然后集合不再有效。在map 中,只有键是const。在set 中,整个对象才是真正的关键。 @Mahesh: const 是必要的,否则你不能用 const 对象调用它们。在我的回答中查看函数f()【参考方案3】:

实际上,C++ 标准(即C++ 0x draft)说(@Xeo 和@Ben Voigt 向我指出这一点):

23.2.4 关联容器5 用于设置和多重设置值类型 与密钥类型相同。对于地图 和multimap它等于pair。关联中的键 容器是不可变的。6 的迭代器 关联容器是 双向迭代器类别。为了 关联容器的值 类型与键类型相同,两者 iterator 和 const_iterator 是 常量迭代器。未指定 是否迭代器和 const_iterator 是同一类型。

所以 VC++ 2008 Dinkumware 实现是错误的。


旧答案:

您收到该错误是因为在 std lib 的某些实现中,set::iteratorset::const_iterator 相同。

例如 libstdc++(与 g++ 一起提供)有它(完整源代码请参见here):

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

在 SGI 的 docs 中它声明:

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 方法。

【讨论】:

【参考方案4】:

让我举一个更详细的例子。至于下面的结构:

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]

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

    将方法uint32_t getCount()...更改为uint32_t getCount() const ...。所以count.getCount() 不会更改count 中的成员。

    uint32_t add(const Count&amp; count)... 更改为uint32_t add(Count&amp; count)...。所以count 不关心更换成员。

关于你的问题,std::set中的对象存储为const StudentT,但是方法getIdgetName不是const,所以你给出了上面的错误。

您也可以查看此问题Meaning of 'const' last in a function declaration of a class? 了解更多详情。

【讨论】:

以上是关于错误:将 xxx 作为 xxx 的“this”参数传递会丢弃限定符的主要内容,如果未能解决你的问题,请参考以下文章

TypeError: this.xxx.substring is not a function的解决办法

1130 - Host'xxx.xxx.xxx.xxx' is not allowed to connect to this MySQL server解决Navicat连接MySQL报

vue路由高级语法糖

React useState 挂钩错误:“xxx”类型的参数不可分配给“SetStateAction<xx>”类型的参数

Ubuntu报“xxx is not in the sudoers file.This incident will be reported” 错误解决方法

Ubuntu报“xxx is not in the sudoers file.This incident will be reported” 错误解决方法