Why am I violating constness [duplicate] - c++

#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;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!

The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
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
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.

Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.

Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
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.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.

Let's me give a more detail example. As to the below struct:
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;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.

Related

I can't redefine operator[] for const structure [duplicate]

#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;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!
The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
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
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.
Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.
Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
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.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.
Let's me give a more detail example. As to the below struct:
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;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.

Why can't a const pointer to a const pointer to a const object be dereferenced to call a member function in the const object? [duplicate]

#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;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!
The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
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
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.
Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.
Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
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.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.
Let's me give a more detail example. As to the below struct:
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;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.

C++ error: passing ‘const umap_int {aka const std::unordered_map<int, int>}’ as ‘this’ argument discards qualifiers [-fpermissive]

I am trying to get a constant reference back by a method for the mapped value of an unordered_map. The unordered_map is a class member. However, the code below does not work and raises the error stated in the title.
I tried to change const umap_int::mapped_type & to const int & which did not work either. The standard example of returning a const reference to a variable of simple datatype (int, double, ...) worked.
#include <unordered_map>
using namespace std;
typedef unordered_map<int, int> umap_int;
class class_A{
public:
class_A(){
for(int k=0; k<3;++k)
M[k] = k;
}
const umap_int::mapped_type & get_M(int key) const{
return M[key];
}
private:
umap_int M;
};
int main(){
class_A A;
return 0;
}
Inside const method you can only call for M its const member functions. Both unordered_map::operator[] overloads are non-const - reference. So you cannot use it inside const get_M. You could remove const qualifier from get_M signature, or use find which has const overload but then you need to handle a case when mapped value doesn't exist for the passed key:
const umap_int::mapped_type & get_M(int key) const {
//return M[key];
auto it = M.find(key);
if (it != M.end())
return it->second;
// do sth here ...
// throw exception
// make static variable with default value which will be accessed
}

error: passing ‘const xxx’ as ‘this’ argument discards qualifiers [-fpermissive] [duplicate]

#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;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!
The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
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
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.
Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.
Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
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.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.
Let's me give a more detail example. As to the below struct:
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;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.

error: passing xxx as 'this' argument of xxx discards qualifiers

#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;
}
In line:
cout << itr->getId() << " " << itr->getName() << endl;
It give an error that:
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'int StudentT::getId()' discards qualifiers
../main.cpp:35: error: passing 'const StudentT' as 'this' argument of 'std::string StudentT::getName()' discards qualifiers
What's wrong with this code? Thank you!
The objects in the std::set are stored as const StudentT. So when you try to call getId() with the const object the compiler detects a problem, mainly you're calling a non-const member function on const object which is not allowed because non-const member functions make NO PROMISE not to modify the object; so the compiler is going to make a safe assumption that getId() might attempt to modify the object but at the same time, it also notices that the object is const; so any attempt to modify the const object should be an error. Hence compiler generates an error message.
The solution is simple: make the functions const as:
int getId() const {
return id;
}
string getName() const {
return name;
}
This is necessary because now you can call getId() and getName() on const objects as:
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
}
As a sidenote, you should implement operator< as :
inline bool operator< (const StudentT & s1, const StudentT & s2)
{
return s1.getId() < s2.getId();
}
Note parameters are now const reference.
Member functions that do not modify the class instance should be declared as const:
int getId() const {
return id;
}
string getName() const {
return name;
}
Anytime you see "discards qualifiers", it's talking about const or volatile.
Actually the C++ standard (i.e. C++ 0x draft) says (tnx to #Xeo & #Ben Voigt for pointing that out to me):
23.2.4 Associative containers
5 For set and multiset the value type
is the same as the key type. For map
and multimap it is equal to pair. Keys in an associative
container are immutable.
6 iterator of
an associative container is of the
bidirectional iterator category. For
associative containers where the value
type is the same as the key type, both
iterator and const_iterator are
constant iterators. It is unspecified
whether or not iterator and
const_iterator are the same type.
So VC++ 2008 Dinkumware implementation is faulty.
Old answer:
You got that error because in certain implementations of the std lib the set::iterator is the same as set::const_iterator.
For example libstdc++ (shipped with g++) has it (see here for the entire source code):
typedef typename _Rep_type::const_iterator iterator;
typedef typename _Rep_type::const_iterator const_iterator;
And in SGI's docs it states:
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.)
On the other hand VC++ 2008 Express compiles your code without complaining that you're calling non const methods on set::iterators.
Let's me give a more detail example. As to the below struct:
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;
}
};
As you see the above, the IDE(CLion), will give tips Non-const function 'getCount' is called on the const object. In the method add count is declared as const object, but the method getCount is not const method, so count.getCount() may change the members in count.
Compile error as below(core message in my compiler):
error: passing 'const xy_stl::Count' as 'this' argument discards qualifiers [-fpermissive]
To solve the above problem, you can:
change the method uint32_t getCount(){...} to uint32_t getCount() const {...}. So count.getCount() won't change the members in count.
or
change uint32_t add(const Count& count){...} to uint32_t add(Count& count){...}. So count don't care about changing members in it.
As to your problem, objects in the std::set are stored as const StudentT, but the method getId and getName are not const, so you give the above error.
You can also see this question Meaning of 'const' last in a function declaration of a class? for more detail.