54

I have a vector as member in a class and I want to return a reference to it through a getVector() function, so as to be able to modify it later. Isn’t it better practice the function getVector() to be const? However I got an error “qualifiers dropped in binding reference of type…” in the following code. What should be modified?

class VectorHolder
{
public:
VectorHolder(const std::vector<int>&);
std::vector<int>& getVector() const;

private:
std::vector<int> myVector;

};

std::vector<int> &VectorHolder::getVector() const
{
return myVector;
}
arjacsoh
  • 8,932
  • 28
  • 106
  • 166

4 Answers4

57

Since it is a const member function, the return type cannot be non-const reference. Make it const:

const std::vector<int> &VectorHolder::getVector() const
{
   return myVector;
}

Now it is okay.

Why is it fine? Because in a const member function, the every member becomes const in such a way that it cannot be modified, which means myVector is a const vector in the function, that is why you have to make the return type const as well, if it returns the reference.

Now you cannot modify the same object. See what you can do and what cannot:

 std::vector<int> & a = x.getVector();       //error - at compile time!

 const std::vector<int> & a = x.getVector(); //ok
 a.push_back(10);                            //error - at compile time!

 std::vector<int>  a = x.getVector();        //ok
 a.push_back(10);                            //ok

By the way, I'm wondering why you need such VectorHolder in the first place.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • In this way is then impossible to modify the returned vector later from the code where you return it? – arjacsoh Dec 05 '11 at 11:10
23

it's not unusual to declare both const and mutable variants, like so:

std::vector<int>& VectorHolder::getVector() {
  return myVector;
}
const std::vector<int>& VectorHolder::getVector() const {
  return myVector;
}

the underlying problem with your program is that you return a non-const reference from a const method.

std::vector<int>& VectorHolder::getVector() const {
  return myVector; // << error: return mutable reference from const method
}

so you make it const using this form:

const std::vector<int>& VectorHolder::getVector() const {
  return myVector; // << ok
}

and when this is in a non const method or the client holds a non-const reference, then you can legally use a non-const method:

std::vector<int>& VectorHolder::getVector() {
  return myVector; // << ok
}

finally, you could return a value (in some cases):

std::vector<int> VectorHolder::getVector() const {
  return myVector; // << ok
}

because the copy requires no mutation and provides no exposure to the internal data.

so you will end up declaring both variants quite often.

the results of declaring both are:

VectorHolder m;
const VectorHolder c;

m.getVector().size(); // << ok
c.getVector().size(); // << ok - no mutation

m.getVector().push_back(a); // << ok
c.getVector().push_back(a); // << error: attempt to mutate const reference because the const vector is returned

so it all works out nicely (apart from the redundancy of the methods).

justin
  • 104,054
  • 14
  • 179
  • 226
3

The function getVector can be declared as const. It returns a reference that can be modified, so while the actual function doesn't modify anything in the class, the caller will be able to modify internal data.

Declare it as:

std::vector<int>& getVector();

If you want a function to return a vector that can't be modified, the use the const modifier on both the vector and the function:

const std::vector<int>& getVector() const;
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
0

The reason is that a const member function should only return const references. This is because in a const function, every data member becomes constant.

Therefore you have to declare the getVector() this way:

std::vector<int> &VectorHolder::getVector() const;
Lev
  • 727
  • 5
  • 17
  • 2
    Regardless to the above, it's, probably, not a good idea to expose your internal container. If some day you will decide to migrate from vector to a map, your users will be affected. I'd suggest to implement iterators instead. – Lev Dec 05 '11 at 11:06