Error passing const as this argument discards qualifiers

Error passing const as this argument discards qualifiers 1-2 days, unlike my previous posts that have been questions for homework already past their due dates (or not school related). However, I’m not asking for code or anything. I just can’t figure out what is causing the errors I’m seeing. I know the main lines […]

Error passing const as this argument discards qualifiers

1-2 days, unlike my previous posts that have been questions for homework already past their due dates (or not school related). However, I’m not asking for code or anything. I just can’t figure out what is causing the errors I’m seeing. I know the main lines causing the issue but not what is actually wrong. I’ve spent quite a while on this and checked this post:
https://stackoverflow.com/questions/26963510/error-passing-const-as-this-argument-of-discards-qualifiers/26963552
But still can’t figure out what I’m doing wrong as I don’t see any constants.

The homework assignment was to fix specific parts so the program can complete it’s intended purpose.

The files I’m working with are:
main.cpp
Triangle.cpp (Contains functions for the class in Triangle.h)
Triangle.h (Contains class and function referencing (I think it’s called?))

I run it using:
g++ -std=c++14 main.cpp Triangle.cpp

The errors I’m getting are:

The main code that’s getting the issue is (lines 135-149 in main.cpp):

I’m trying to write to a file with a format and with data from the class.

I know 3 files isn’t the best to be asking questions about, I really tried to figure out the issue myself but I’ve spent hours on this and have had no luck. I’d really appreciate some help!

Note: If you need an example input file then you can use a text file with:

Edit: Updated Error. Posted wrong errors before I think.

I didn’t actually download and compile your code, but just looking at:

main.cpp:139:37: error: passing ‘const value_type ’ as ‘this’ argument discards qualifiers [-fpermissive]
ts[i].getSides(side1, side2, side3);

«discards qualifiers» is the compiler’s way of saying that you’re trying to modify (or potentially could modify) an object that was declared as const.

In your writeReport function, void writeReport( const vector & ts)
you are passing the vector ts as const reference. That means you can’t use a function that could potentially modify the data of one of the elements of the vector (or the vector itself)*.

ts[i].getSides(side1, side2, side3); getSides is not declared with const correctness in your class definition, so to the compiler, getSides is a function that could potentially modify the object ts[i].

In Triangle.h, you need to make your getSides declaration look like this instead:
void getSides( double &side1, double &side2, double &side3) const ;
Emphasis on the const at the end.
And remove the getSides declaration that doesn’t use references, I think that will just cause more errors.

Let us know if adding const there makes the error disappear.

Ohh, thank you very much for your response (and explaining why)!

After checking the stackoverflow page I had tried something similar, but I made the mistake of putting the «const» after the statement «getSides(side1, side2, side3)» instead of after the function statement(s).

After adding the const where you said and in Triangle.cpp, it worked perfectly.

«And remove the getSides declaration that doesn’t use references, I think that will just cause more errors.«
Should I still remove the getSides declaration that doesn’t use references if the code compiles without errors? (May be a dumb question, but sometimes even though it doesn’t cause errors it could still be doing something wrong). Also, where were you referring to?

Источник

This page documents longer explanations for diagnostics in the C and C++ front-ends. Contact the gcc-help mailing list to propose new content and/or get access to edit this page yourself (unfortunately due to repeated spam attacks you need to contact a human being to get editing rights, but doing so is easy).

TODO

  • Add more diagnostics to this list!
  • Some of the preprocessor/compiler/linker/runtime errors described in An Introduction to GCC might be useful here (N.B. that text is licensed under the GFDL so can’t be simply copied here verbatim).

Contents

    1. assuming signed overflow does not occur when simplifying conditional to constant [-Wstrict-overflow]
    2. %D may be used uninitialized [-Wuninitialized]
    3. warning: passing argument %d of %D from incompatible pointer type; note: expected ‘const char **’ but argument is of type ‘char **’
    4. warning: switch condition has boolean value [-Wswitch-bool]
  1. C++ FE

    1. error: uninitialized const ‘d’ [-fpermissive], note: ‘const class D’ has no user-provided default constructor
    2. error: there are no arguments to ‘f’ that depend on a template parameter, so a declaration of ‘f’ must be available
    3. undefined reference to `S::a’
    4. undefined reference to vtable for X
    5. warning: deleting object of polymorphic class type ‘Base’ which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
    6. error: passing ‘const X’ as ‘this’ argument discards qualifiers [-fpermissive]
    7. «control reaches end of non-void function» after a switch using an enum

assuming signed overflow does not occur when simplifying conditional to constant [-Wstrict-overflow]

[ Permalink ]

Signed overflow is undefined behavior according to the C/C++ language. Compilers rely on the fact that a valid program does not contain undefined behavior to optimize code, by assuming that conditions which would lead to undefined behaviour are always false (which is true for valid programs). The -Wstrict-overflow warning does not always mean that the code has a bug, only that some condition that could theoretically happen given the part of the code that the compiler is optimizing (which after inlining and other optimizations may be quite different from what the user wrote) never happens in practice. On the other hand, it may indeed denote a bug, either because the user assumed that signed overflow wraps like unsigned overflow or because the signed overflow does happen in practice.

Given the difficulty of distinguishing, at compilation time, between user errors and valid optimizations, this warning was removed in GCC 8: «-fno-strict-overflow is now mapped to -fwrapv and signed integer overflow is now undefined by default at all optimization levels. Using -fsanitize=signed-integer-overflow is now the preferred way to audit code, -Wstrict-overflow is deprecated.»

%D may be used uninitialized [-Wuninitialized]

[ Permalink ]

A variable that has not been initialized is read at some point in the code. Reading a uninitialized variable leads to undefined behaviour. Whether a variable is assigned a value before reading it cannot be decided in general. Depending on the optimization level, the version of GCC and the particular code, GCC may not be able to detect that a variable is actually always initialized and give a false warning. On the other hand, it may be able to detect that the variable is never used apart from uninitialized use and not warn.

See also -Wuninitialized in GCC manual

warning: passing argument %d of %D from incompatible pointer type; note: expected ‘const char **’ but argument is of type ‘char **’

[ Permalink ]

See the C++ FAQ Lite (this question applies to both C and C++):

http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

warning: switch condition has boolean value [-Wswitch-bool]

Boolean variables in switch conditions are very uncommon and often indicate that the wrong variable is being used. Boolean expressions are even less common, and normally indicate that a bit-wise operator (& instead of &&, or | instead of ||) was intended. There may be valid cases that use a boolean in a switch:

switch (bool)
    {
    case true: X();
    default: Y();
    }

however, all of those cases can be written (arguably, more clearly) using if-else:

if(bool)
  X();
Y();

C++ FE

error: uninitialized const ‘d’ [-fpermissive], note: ‘const class D’ has no user-provided default constructor

[ Permalink ]

   1    class C { };
   2    class D : public C { };
   3    const D d;

As mandated by the C++ standard (8.5 [decl.init], para 9 in C++03, para 6 in C++0x), G++ does not allows objects of const-qualified type to be default initialized unless the type has a user-declared default constructor. Code that fails to compile can be fixed by providing an initializer e.g.

  • You can use -fpermissive to allow the old, non-conforming behaviour.

error: there are no arguments to ‘f’ that depend on a template parameter, so a declaration of ‘f’ must be available

[ Permalink ]

   1     template<typename T>
   2     struct base
   3     {
   4       void f();
   5     };
   6     template<typename T>
   7     struct derived : public base<T>
   8     {
   9       void g() { f(); }
  10     };

The C++ standard says (14.6.2 [temp.dep] para 3) that lookup of unqualified names (such as f in the example) does not look in a «dependent base», i.e. a base class which depends on a template parameter. To tell the compiler that f is a member and lookup should include dependent bases, it must be qualified as either this->f() or base<T>::f(). See Name lookup, templates, and accessing members of base classes or the C++ templates FAQ or C++ FAQ for further details.

undefined reference to `S::a’

[ Permalink ]

Some people are surprised to get a linker error when using static const members in conditional expressions (i.e. the ?: operator) like so:

   1 struct S
   2 {
   3     static const int a = 1;
   4     static const int b = 2;
   5 };
   6 int main(int argc, char** argv)
   7 {
   8    return argc > 1 ? S::a : S::b;
   9 }

This program is invalid and will fail to link:

/tmp/ccATW9fH.o: In function `main':
n.cc:8: undefined reference to `S::a'
n.cc:8: undefined reference to `S::b'
collect2: error: ld returned 1 exit status

The C++ standard says ([basic.def.odr] 3.2 paragraph 2) «A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.» and (paragraph 3) «Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.»

In the example above the lvalue-to-rvalue conversion cannot be applied, because (x?a:b) is an lvalue when a and b are both lvalues of the same type.

The same link error can happen if the static const member is used as an argument to a function which has reference parameters e.g.

   1 #include 
   2 struct S
   3 {
   4     static const int a = 1;
   5     static const int b = 2;
   6 };
   7 int main(int argc, char** argv)
   8 {
   9    return std::max(S::a, S::b);
  10 }

It should be noted that with optimization enabled the variables may not be referenced, due to inlining or constant propagation, and so linking might succeed, but the program is still technically invalid.

The program can be fixed by providing a definition of the variables and/or by forcing either variable to be converted to an rvalue:

   1 struct S
   2 {
   3     static const int a = 1;
   4     static const int b = 2;
   5 };
   6 const int S::a;  
   7 const int S::b;  
   8 int main(int argc, char** argv)
   9 {
  10    return argc > 1 ? S::a : (int)S::b;
  11 }

See also Declare and Define Static Members and How do I define an in-class constant?

N.B. In February 2012 DR 712 updated the language so that the static variables in the conditional expressions above are no longer odr-used, so definitions are no longer required in the conditional expression case. Definitions are still required for cases like the std::max() example. That DR is not implemented by any version of G++ (at the time of writing GCC 4.7.1 is the latest release.)

undefined reference to vtable for X

[ Permalink ]

Every polymorphic class requires a virtual table or vtable describing the type and its virtual functions. Whenever possible the vtable will only be generated and output in a single object file rather than generating the vtable in every object file which refers to the class (which might be hundreds of objects that include a header but don’t actually use the class.) The cross-platform C++ ABI states that the vtable will be output in the object file that contains the definition of the key function, which is defined as the first non-inline, non-pure, virtual function declared in the class. If you do not provide a definition for the key function (or fail to link to the file providing the definition) then the linker will not be able to find the class’ vtable.

In this example, X::i() is the key function because the destructor is pure virtual, X::f() is not virtual and X::g() and X::h() are inline:

   1 class X {
   2 public:
   3   virtual ~X() = 0;
   4   void f();
   5   virtual void g() { }
   6   virtual void h();
   7   virtual void i();
   8   virtual void j();
   9 };
  10 inline void X::h() { }

To fix the linker error be sure you have provided a definition for the first non-inline non-pure virtual function declared in the class (X::i() in the example above). It may be possible to improve the error message, although this is far from trivial.

For a more detailed description of this error see Missing Key Function in the LLD documentation.

warning: deleting object of polymorphic class type ‘Base’ which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]

[ Permalink ]

Deleting an object through a pointer to its base class will only run the derived class destructor if the base class destructor is virtual. If the destructor of the base class is not virtual then the delete operation has undefined behaviour, often resulting in (but not limited to) leaking memory and other resources managed by the derived class.

G++ will warn when delete is used with a polymorphic type (i.e. a type that has virtual functions) that does not have a virtual destructor e.g.

   1 class Base {
   2 public:
   3   virtual void foo() = 0;
   4 };
   5 
   6 class Derived : public Base {
   7 public:
   8   virtual void foo() {}
   9   ~Derived()         {}
  10 };
  11 
  12 void bar(Base* p)
  13 {
  14   p->foo();
  15   delete p;  
  16 }
  17 
  18 void baz(Derived* p)
  19 {
  20   p->foo();
  21   delete p;  
  22 }
  23 
  24 int main() {
  25   Derived* d1 = new Derived();
  26   bar(d1);
  27   Derived* d2 = new Derived();
  28   baz(d2);
  29 }

This code produces two warnings:

d.C: In function 'void bar(Base*)':
d.C:15:10: warning: deleting object of abstract class type 'Base' which has non-virtual destructor will cause undefined behaviour [-Wdelete-non-virtual-dtor]
   delete p;  // warning!
          ^
d.C: In function 'void baz(Derived*)':
d.C:21:10: warning: deleting object of polymorphic class type 'Derived' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor]
   delete p;  // warning!
          ^

The first warning says bar will cause undefined behaviour, because Base is an abstract class so the actual object being deleted must be some type derived from Base (because an abstract class can only be used as a base class of another type) and because there is no virtual destructor the derived class destructor will not be called, resulting in undefined behaviour.

The second warning says baz might cause undefined behaviour, because the delete operation is safe if the object being destroyed is a Derived, but unsafe if it is some type derived from Derived. In the code above the call to baz is actually safe, but G++ still issues a warning for baz because a class that has virtual functions suggests it is likely (or at least possible) it will be used as a base class, in which case the delete operation would be unsafe e.g.

   1 
   2 class MoreDerived : public Derived {
   3   std::string str;
   4 public:
   5   virtual void foo() { }
   6   ~MoreDerived() { }
   7 };
   8 
   9 int main() {
  10   MoreDerived* md = new MoreDerived();
  11   baz(md);
  12 }

In this example the MoreDerived destructor will not execute, causing a memory leak.

The will cause undefined behaviour warning always indicates a real bug that should be fixed, either by adding a virtual destructor, or by deleting the correct type instead of the base class. Note that even a pure virtual destructor requires an implementation: [C++11: 12.4/9]: A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual. For example:

   1 class Base {
   2 public:
   3   virtual void foo() = 0;
   4   virtual ~Base() = 0;
   5 };
   6 inline Base::~Base() {}

The might cause undefined behaviour warning indicates a potential bug, but the warning will sometimes be issued for correct code, as in the first example above. Adding a virtual destructor will ensure the code is safe and so prevents the warning. Alternatively, the warning will not be issued if the compiler knows the class cannot be derived from i.e. if the class uses the C++11 final specifier

   1 class Derived final : public Base {
   2   
   3 };

In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.)

(The -Wdelete-non-virtual-dtor warning and final specifier are supported by GCC 4.7.0 and later releases.)

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

[ Permalink ]

This error is given when trying to call a non-const member function on a const object or from inside a const member function. A non-const member function might modify the object, which is not allowed through a const access path.

   1 class X {
   2 public:
   3   void update(int n) { m_counter + n; }
   4   void doSomething() const { update(1); }
   5 private:
   6   int m_counter = 0;
   7 };
   8 int main() {
   9   X x;
  10   x.doSomething();
  11 }

The solution might be to add const to the member function (if it doesn’t really need to modify anything), or to remove const elsewhere to get a modifiable pointer/reference to the object. For the example above, X::doSomething() should not be const if it needs to call X::update(int)

«control reaches end of non-void function» after a switch using an enum

[ Permalink ]

Many users are surprised to get a warning for code like this:

enum class E { E1, E2 };

int to_int(E e) {
  switch (e) {
  case E::E1:
    return 1;
  case E::E2:
    return 2;
  }
}

e.cc: In function ‘int to_int(E)’:
e.cc:10:1: warning: control reaches end of non-void function [-Wreturn-type]
    10 | }
      | ^

It’s a common misunderstanding that variables of type E can only ever have two values, either E::E1 or E::E2, and so the warning is wrong. In fact G++ is correct. You can explicitly create a variable with a different value and pass it to the function, for example to_int(E{3}) or to_int((E)-4). For those calls, neither switch-case will match, and the program’s control flow will reach the end of the function, resulting in undefined behaviour.

For an enumeration type with a fixed underlying type any value of the underlying type can be converted to the enum in this way. For an enumeration type without a fixed underlying type, the range of valid values that can be created depends on the enumerators declared for it (but is still not restricted to just the specific values correspnding to the enumerator constants). An enumeration type has a fixed underlying type if it is a scoped enumeration (i.e. enum class) or if it is declared with an enum-base (e.g. enum F : int { … }).

To prevent the warning, either add a default: case to the switch to handle other values, or inform the compiler that your program will never pass any other values, like so:

int to_int(E e) {
  switch (e) {
  case E::E1:
    return 1;
  case E::E2:
    return 2;
  }
  // promise the compiler that other values will never
  // be passed to this function:
  __builtin_unreachable();
}

error: passing ‘const value_type {aka const Triangle}’ as ‘this’ argument discards qualifiers…

Okay, I should note that this is homework that is due in ~1-2 days, unlike my previous posts that have been questions for homework already past their due dates (or not school related). However, I’m not asking for code or anything. I just can’t figure out what is causing the errors I’m seeing. I know the main lines causing the issue but not what is actually wrong. I’ve spent quite a while on this and checked this post:
https://stackoverflow.com/questions/26963510/error-passing-const-as-this-argument-of-discards-qualifiers/26963552
But still can’t figure out what I’m doing wrong as I don’t see any constants.

The homework assignment was to fix specific parts so the program can complete it’s intended purpose.

The files I’m working with are:
main.cpp
Triangle.cpp (Contains functions for the class in Triangle.h)
Triangle.h (Contains class and function referencing (I think it’s called?))

I run it using:
g++ -std=c++14 main.cpp Triangle.cpp

The errors I’m getting are:

1
2
3
4
5
6
7
main.cpp: In function ‘void writeReport(const std::vector<Triangle>&)’:
main.cpp:139:37: error: passing ‘const value_type {aka const Triangle}’ as ‘this’ argument discards qualifiers [-fpermissive]
   ts[i].getSides(side1, side2, side3);
                                     ^
In file included from main.cpp:22:0:
Triangle.h:20:7: note:   in call to ‘void Triangle::getSides(double&, double&, double&)’
  void getSides(double &side1, double &side2, double &side3);

The main code that’s getting the issue is (lines 135-149 in main.cpp):

I’m trying to write to a file with a format and with data from the class.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
		// FIXME7
		// Output each triangle's information as shown in the sample output.
		// Use proper formatting
		//fout << "FIXME" << endl; // comment this out when fixed
		ts[i].getSides(side1, side2, side3);
		fout << setw(5) << i << setw(8) << side1 << setw(8) << 
			side2 << setw(8) << side3 << setw(8) << "area" << 
			setw(10) << "perimeter" << setw(17) << "type" << endl;
		
		/*
		ts[i].getSides(side1, side2, side3);
		fout << setw(5) << i << setw(8) << side1 << setw(8) << 
			side2 << setw(8) << side3 << setw(8) << ts[i].getArea() << 
			setw(10) << ts[i].getPerimeter() << setw(17) << ts[i].getType() << endl;
		*/

Full Code / Files:
main.cpp: http://cpp.sh/8j7vu
Triangle.h: http://cpp.sh/6dl2z
Triangle.cpp: http://cpp.sh/7geyd

I know 3 files isn’t the best to be asking questions about, I really tried to figure out the issue myself but I’ve spent hours on this and have had no luck. I’d really appreciate some help!

Thanks!

Note: If you need an example input file then you can use a text file with:

1
2
3
2.5 2.0 2.0
5.0 5.0 5.0
2.0 3.0 4.0

Edit: Updated Error. Posted wrong errors before I think.

Last edited on

I didn’t actually download and compile your code, but just looking at:

main.cpp:139:37: error: passing ‘const value_type {aka const Triangle}’ as ‘this’ argument discards qualifiers [-fpermissive]
ts[i].getSides(side1, side2, side3);

«discards qualifiers» is the compiler’s way of saying that you’re trying to modify (or potentially could modify) an object that was declared as const.

In your writeReport function, void writeReport(const vector<Triangle>& ts)
you are passing the vector ts as const reference. That means you can’t use a function that could potentially modify the data of one of the elements of the vector (or the vector itself)*.

ts[i].getSides(side1, side2, side3);
getSides is not declared with const correctness in your class definition, so to the compiler, getSides is a function that could potentially modify the object ts[i].

In Triangle.h, you need to make your getSides declaration look like this instead:
void getSides(double &side1, double &side2, double &side3) const;
Emphasis on the const at the end.
And remove the getSides declaration that doesn’t use references, I think that will just cause more errors.

Let us know if adding const there makes the error disappear.

https://isocpp.org/wiki/faq/const-correctness

*note: The constness of data pointed to by pointers doesn’t propagate, this can sometimes cause confusion. But you don’t need to worry about that here.
https://stackoverflow.com/questions/4729820/propagate-constness-to-data-pointed-by-member-variables

Last edited on

Ohh, thank you very much for your response (and explaining why)!

After checking the stackoverflow page I had tried something similar, but I made the mistake of putting the «const» after the statement «getSides(side1, side2, side3)» instead of after the function statement(s).

After adding the const where you said and in Triangle.cpp, it worked perfectly.

«And remove the getSides declaration that doesn’t use references, I think that will just cause more errors.«
Should I still remove the getSides declaration that doesn’t use references if the code compiles without errors? (May be a dumb question, but sometimes even though it doesn’t cause errors it could still be doing something wrong). Also, where were you referring to?

Nevermind about that last part… that was me just misreading your source code!

Glad it works.

Ah okay, thanks!

Edit: Closing this, I wasn’t able to figure it out so I decided I’d just leave it as is. I completed the bonus questions so I should still get 100% on the assignment. As for the learning aspect of it, oh well. I need to focus on other assignments too.

Thank you for the original help fixing the error! =)
=========================================

Okay, was going to mark as solved but I’m having trouble with 2 more parts that I’ve been trying to figure out for the last 3 hours.
1. The findArea() function in Triangle.cpp. I think I set it up properly to actually find the area. But I think I need to call the function and no matter what I try it doesn’t work.
2. Sorting triangle ( in main() from main.cpp ). Not sure how to use the sort() for this, all of my attempts have failed. Also, I don’t fully understand what I’m supposed to sort. I guessed the sides of the triangles which is what I was trying to sort, but one of the comments says I should use this for it:
friend bool operator<(const Triangle &, const Triangle &);
Which compares the areas of t1 and t2 (triangle objects).

Notes:
— void Triangle::findArea() {} can be found in Triangle.cpp at line 43.
— The parts where I’m trying to use findArea() & getArea() are in main.cpp at the lines: 143-148.
— I’m guessing I’ll need to get the area fixed before I can fix sort because in Triangle.h there’s a note that says:

1
2
// use this friend function to compare and sort triangles
friend bool operator<(const Triangle &, const Triangle &);

And that ^ function is found in Triangle.cpp:

1
2
3
4
5
6
7
8
9
10
// friend function to Triangle class
bool operator<(const Triangle& t1, const Triangle& t2) {
    // FIXME12: - fixed
	// return true if t1's area is smaller than t2's area 
    // false otherwise
	if (t1.getArea() < t2.getArea())
		return true;
	else
		return false;
}

Latest Code:
main.cpp: http://cpp.sh/4bsfe
Triangle.h: http://cpp.sh/9hrsh
Triangle.cpp: http://cpp.sh/2o4pd

Input File:

1
2
3
2.5 2.0 2.0
5.0 5.0 5.0
2.0 3.0 4.0

Output File:
(Everything works except the area)

1
2
3
4
5
6
7
8
9
*****************************************************************
                    Triangle Information
*****************************************************************
    #  side 1  side 2  side 3    area perimeter             type
=================================================================
    1    2.50    2.00    2.00    0.00      6.50        Isosceles
    2    5.00    5.00    5.00    0.00     15.00      Equilateral
    3    2.00    3.00    4.00    0.00      9.00          Scalene
=================================================================

Edit: Closing this, I wasn’t able to figure it out so I decided I’d just leave it as is. I completed the bonus questions so I should still get 100% on the assignment. As for the learning aspect of it, oh well. I need to focus on other assignments too.

Thank you for the original help fixing the error! =)

Last edited on

Topic archived. No new replies allowed.

Member Avatar

11 Years Ago

Hey, it’s me again. Again with a topic that has been covered here but reading through the old threads didnt help me to solve my problem. And I am pretty clueless at the moment.

Consider the class passenger_queue with 2 functions, namely:

int passenger_queue::get_passengers_waiting() const
{
  // Insert your code here. Use the iterator defined in this class.
  int sum = 0;

  }
  return sum;


}

and

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_)
{
    return _waiting_passengers[floor_];
}

member variables are:

typedef std::map<int, std::vector<passenger*> >  p_map;
  p_map _waiting_passengers;
    
  std::vector<passenger> _passengers;

First of all the comment in the get_passengers_waiting. Apart from the constructor which I didnt include in the code, there is no iterator defined in this class (or else I dont know how an iterator definition looks like).

So my first solution is the following (which seems to work):

int passenger_queue::get_passengers_waiting() const
{
  // Insert your code here. Use the iterator defined in this class.
  int sum = 0;
  for (p_map::const_iterator it = _waiting_passengers.begin(); it != _waiting_passengers.end(); ++it) {
    sum+= it->second.size();
  }
  return sum;
}

I dont need the function passengers_at_floor at all. Now I think the idea would be to use that function but then I run into trouble — passing const as this discards qualifiers. hence the title. What I try is the following:

int passenger_queue::get_passengers_waiting() const
{
  // Insert your code here. Use the iterator defined in this class.
  int sum = 0;
  for (p_map::const_iterator it = _waiting_passengers.begin(); it != _waiting_passengers.end(); ++it) {
    sum+= passengers_at_floor((it->first)).size();
  }
  return sum;
}

which gives me the error:

error: passing ‘const passenger_queue’ as ‘this’ argument of ‘std::vector<passenger*, std::allocator<passenger*> >& passenger_queue::passengers_at_floor(int)’ discards qualifiers

I tried to use iterator instead of const_iterator but that doesnt go down well with the const in the get_passengers_waiting(). So honestly I wouldnt know how to get to the correct result with the use of the passengers_at_floor().

Can anyone point me in the right direction?

I appreciate any help and I hope I wasnt too messy.

(If mike is reading this — I hear you, no leading _ but its still from the same assignment paper :))


Recommended Answers

It could be this function

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_)

Try changing it to

std::vector<passenger*>& passenger_queue::passengers_at_floor(const int floor_)

Jump to Post

Oh, that’s right, if you use a std::map, the operator[] does not exist in the const form because if the index (or key value) does not exist, a new element will be created. So, for the const version, you need to use the find() function instead which will …

Jump to Post

The find function returns a const_iterator in the map, you have to check that it is valid and then output it, and you also have to deal with the fact that the iterator might be invalid if the element does not exist in the map.

const std::vector<passenger*>& …

Jump to Post

All 11 Replies

Member Avatar

11 Years Ago

It could be this function

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_)

Try changing it to

std::vector<passenger*>& passenger_queue::passengers_at_floor(const int floor_)

Member Avatar

11 Years Ago

I just tried that but I didnt help. But am I right assuming that it->first is a const int due to the iterator being constant and you wanted to match parameters?

Member Avatar

11 Years Ago

I just tried that but I didnt help. But am I right assuming that it->first is a const int due to the iterator being constant and you wanted to match parameters?

I was mistaken, because the function

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_)

makes a copy of the const data member first, its allowed.

Member Avatar


arkoenig

340



Practically a Master Poster


11 Years Ago

I suspect the solution is

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const

The point is that at present, passengers_at_floor is permitted to modify its object, but you’re passing it a const object, namely the key from a map.

So you need to add const to the definition of passengers_at_floor, as a promise that it will not modify its object. Of course you need to add it to the declaration inside the class as well, not just to the definition.

Member Avatar


mike_2000_17

2,669



21st Century Viking



Team Colleague



Featured Poster


11 Years Ago

This function:

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const

Has a big flaw, which results in the error you are getting. Since the function is const, it means that you only have read-only access to all its data members. But then, you try to return a non-const reference to a data member from that function. This simply cannot work, and hence, the error you get (either you put the const at the end and you get a «discards qualifiers» on the return type, or you don’t put the const and you get a «discards qualifiers» on the this pointer when the function is called). The solution is simple, define both versions:

//make a non-const function that returns a non-const reference: 
std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_);
//make a const function that returns a const reference:
const std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const;

Both implementations of the above functions are exactly the same. When you call the function with a const object, the const function will be called and a const reference will be returned (and vice-versa if called with a non-const object). This is the proper, and usual way to do this.

Member Avatar


Fbody

682



Posting Maven



Featured Poster


11 Years Ago

I suspect the solution is

std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const

The point is that at present, passengers_at_floor is permitted to modify its object, but you’re passing it a const object, namely the key from a map.

So you need to add const to the definition of passengers_at_floor, as a promise that it will not modify its object. Of course you need to add it to the declaration inside the class as well, not just to the definition.

Agreed. The OP is trying to call a non-const function from a const function. That’s not allowed…

Member Avatar

11 Years Ago

//make a non-const function that returns a non-const reference: 
std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_);
//make a const function that returns a const reference:
const std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const;

So if I understood correctly:

I declared the const and non const version of this function in the header and implemented both in the cpp file. The function body is the same.

If I do this and then compile I get the following error: /Users/phi/Desktop/task_4/passenger_queue.cpp:38:0 /Users/phi/Desktop/task_4/passenger_queue.cpp:38: error: passing 'const std::map<int, std::vector<passenger*, std::allocator<passenger*> >, std::less<int>, std::allocator<std::pair<const int, std::vector<passenger*, std::allocator<passenger*> > > > >' as 'this' argument of '_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = std::vector<passenger*, std::allocator<passenger*> >, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, std::vector<passenger*, std::allocator<passenger*> > > >]' discards qualifiers

Member Avatar


mike_2000_17

2,669



21st Century Viking



Team Colleague



Featured Poster


11 Years Ago

Oh, that’s right, if you use a std::map, the operator[] does not exist in the const form because if the index (or key value) does not exist, a new element will be created. So, for the const version, you need to use the find() function instead which will just find the element corresponding to a key (or an invalid iterator if the key does not exist).

Member Avatar

11 Years Ago

Sorry its me again. Trying to access the map with find gives me following error: error: invalid initialization of reference of type 'const std::vector<passenger*, std::allocator<passenger*> >&' from expression of type 'std::_Rb_tree_const_iterator<std::pair<const int, std::vector<passenger*, std::allocator<passenger*> > > >' the function looks like this. Sorry, I just dont seem to get it.

const std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const
{
    return _waiting_passengers.find(floor_);
}

Member Avatar


mike_2000_17

2,669



21st Century Viking



Team Colleague



Featured Poster


11 Years Ago

The find function returns a const_iterator in the map, you have to check that it is valid and then output it, and you also have to deal with the fact that the iterator might be invalid if the element does not exist in the map.

const std::vector<passenger*>& passenger_queue::passengers_at_floor(int floor_) const
{
  std::map< std::vector<passenger*> >::const_iterator it = _waiting_passengers.find(floor_);
  if(it != _waiting_passengers.end())
    return *it;
  else
    return std::vector<passenger*>(); //or throw an exception.
}

Member Avatar

11 Years Ago

It works!
Thanks everyone for their big help.

fibbo


Reply to this topic

Be a part of the DaniWeb community

We’re a friendly, industry-focused community of developers, IT pros, digital marketers,
and technology enthusiasts meeting, networking, learning, and sharing knowledge.

Пишу модель, унаследованную от абстрактной QAbatractTableModel. Всё по феншую, методы, все, что надо переписал. Но решил я кэшировать данные в свойстве cache. Следовательно надо менять метод data и setData. В итоге получилось:

QVariant MyModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid()) return QVariant();

    if (!cache.contains(m_course)) {
        QMap<QDate, Week> weeks;
        Week week;
        QVector<ScheduleItemPrintable> day;
        for (int nDay = 0; nDay < 7; ++nDay) {
            for (int nDoublePeriod = 0; nDoublePeriod < 6; ++nDoublePeriod)
                day << ScheduleItemPrintable();
            week << day;
        }
        weeks.insert(m_monday, week);
        cache.insert(m_course, weeks); // ошибка
    }
    //...
}

Интерфейс класса модели:

class MyModel : public QAbstractTableModel
{
    Q_OBJECT
private:
    QStringList hheader;

    typedef QVector<QVector<ScheduleItemPrintable> > Week;
    QMap<QString, QMap<QDate, Week> > cache;

    QString m_course;
    QDate m_monday;
public:
    explicit MyModel(QObject *parent = 0);

    int rowCount(const QModelIndex &parent) const;
    int columnCount(const QModelIndex &parent) const;
    Qt::ItemFlags flags(const QModelIndex &index) const;
    QVariant headerData(int section, Qt::Orientation orientation, int role) const;
    bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role);
    QVariant data(const QModelIndex &index, int role) const;
    bool setData(const QModelIndex &index, const QVariant &value, int role);
};

В помеченном месте в первом листинге возникает ошибка:

error: passing 
'const QMap<QString, QMap<QDate, QVector<QVector<ScheduleItemPrintable> > > >'
as 'this' argument of 'QMap<Key, T>::iterator QMap<Key, T>::insert(const Key&, const T&) 
[with Key = QString; T = QMap<QDate, QVector<QVector<ScheduleItemPrintable> > >]' 
discards qualifiers [-fpermissive] cache.insert(m_course, weeks);

Вот и не пойму. Вроде бы всё законно. Свойство лежит в объекте и доступ из методов есть. Что не так?
P. S.: проблема решена с указателем на кэш, но всё же интересно, почему простым объектом не обойтись?

    msm.ru

    Нравится ресурс?

    Помоги проекту!

    !
    Правила раздела *nix / gcc / Eclipse / Qt / wxWidgets / GTK+

    • При создании темы ОБЯЗАТЕЛЬНО указывайте версию тулкита / библиотеки / компилятора.
    • Перед тем как задать вопрос, сформулируйте его правильно, чтобы вас могли понять.
    • Нарушение Правил может повлечь наказание со стороны модераторов.

    Полезные ссылки:
    user posted image Boost по-русски
    user posted image Qt по-русски

    >
    Ошибка. Разьясните в чем.

    • Подписаться на тему
    • Сообщить другу
    • Скачать/распечатать тему



    Сообщ.
    #1

    ,
    22.02.08, 02:48

      Member

      **

      Рейтинг (т): 1

      Есть функция

      ExpandedWrap disabled

        bool newMinute(const Options&, const MinuteOptions&, const QString&);

      В ее теле производиться вызов

      ExpandedWrap disabled

        db.setHostName(options.getDBHost());

      (db это QSqlDatabase)

      Методы

      ExpandedWrap disabled

        void QSqlDatabase::setDatabaseName ( const QString & name );

               const QString& Options::getDBHost();

      Так вот в месте вызова db.setHostName(options.getDBHost()) происходит:
      «ошибка passing ‘const Options’ as ‘this’ argument of ‘const QString& Options::getDBHost()’ discards qualifiers»

      Объясните пожалуйсто в чем конфликт? Как его исправить?


      YuriyRusinov



      Сообщ.
      #2

      ,
      22.02.08, 05:42

        Full Member

        ***

        Рейтинг (т): 31

        Функция getDBHost() твоего класса Options должна быть помечена квалификатором const. Примерно так const QString& Options::getDBHost() const;

        Сообщение отредактировано: YuriyRusinov — 22.02.08, 06:02


        Star62



        Сообщ.
        #3

        ,
        22.02.08, 08:17

          Member

          **

          Рейтинг (т): 1

          Спасибо помогло.
          Но мне все таки интересно почему мой вариант был не работоспособен?


          YuriyRusinov



          Сообщ.
          #4

          ,
          22.02.08, 09:10

            Full Member

            ***

            Рейтинг (т): 31

            Потому что у тебя стоит константная ссылка на объект класса Options, а если функция-член этого класса не является константной, то компилятор сообщает об ошибке, что мол пытаешься изменить константный объект.


            Star62



            Сообщ.
            #5

            ,
            22.02.08, 11:56

              Member

              **

              Рейтинг (т): 1

              Значит если объект передается по константной ссылке, все его методы (функции-члены в секции Public) использующиеся в функции в которую передан объект, должны быть константными? Я правильно понял?


              YuriyRusinov



              Сообщ.
              #6

              ,
              22.02.08, 16:12

                Full Member

                ***

                Рейтинг (т): 31

                Нет, если объект передан по константной ссылке, то должны вызываться только константные методы.

                ExpandedWrap disabled

                  class A

                  {

                      private:

                          int n;

                      public:

                          A (int n0=0);

                          A (const A& a);

                          int getValue () const { return n; }

                          void setValue (int N) { n=N; }

                  };

                  int f(const A& x)

                  {

                      …

                      x.setValue (5); // ошибка

                      int n = x.getValue (); // правильно

                  }


                Star62



                Сообщ.
                #7

                ,
                23.02.08, 07:18

                  Member

                  **

                  Рейтинг (т): 1

                  Понятно спасибо.

                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                  0 пользователей:

                  • Предыдущая тема
                  • Кроссплатформенный C/C++: cl/gcc/Qt/Gtk+/WxWidgets
                  • Следующая тема

                  Рейтинг@Mail.ru

                  [ Script execution time: 0,0227 ]   [ 16 queries used ]   [ Generated: 9.02.23, 14:57 GMT ]  

                  Понравилась статья? Поделить с друзьями:
                • Error parsing xml unbound prefix error
                • Error parsing uri scheme must be mongodb or mongodb srv
                • Error parsing token перевод
                • Error parsing timestamp
                • Error parsing the server clients xml file