Question

Consider the following minimal example.

#include <vector>

class Data
{
    std::vector<int>& v;
public:
    Data(std::vector<int>& _v) : v(_v) {}
    Data(const std::vector<int>& _v) : v(_v) {} // error!
};

int main()
{
    std::vector<int> v;
    const std::vector<int> c_v;
    Data d(v);
    Data const_d(c_v);

    return 0;
}

This does not compile. The whole output from g++ -Wall below.

const.cpp: In constructor ‘Data::Data(const std::vector<int>&)’:
const.cpp:8:41: error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘const std::vector<int>’

The reason is clear to me: The const keyword is upset about my cast in line 8. The issue: I really sometimes need the Data class with std::vector, but sometimes with const std::vector. Like having two classes: One for reading into Data, and one for reading from Data. However, I do not like to write two Data classes with almost redundant functions. My questions:

  • Can you give a nice solution to how I can achieve what I try to do in main()? C++11 solutions are pretty welcome, too :)
  • Is this the reason for iterator and const_iterator?
Was it helpful?

Solution

const-ness of data members needs to be known at compile time. If you "sometimes" need a reference to a const vector and sometimes non-const, you should create a class hierarchy with the base abstract class containing the common functionality, and inherit it in two Data classes: Data and ConstData. The Data would contain a non-const vector, and ConstData would contain a const vector. This way you would not duplicate any logic, while two separate classes would contain two references of different const-ness.

Here is an example:

class AbstractData {
public:
    // Common functions use vect() and const_vect()
    void common_function1();
    void common_function2();
protected:
    virtual vector<int>& vect() const = 0;
    virtual const vector<int>& const_vect() const = 0;
};

class Data : public AbstractData {
    vector<int>& v;
public:
    Data(vector<int>& _v) : v(_v) {}
protected:
    vector<int>& vect() const {
        return v;
    }
    const vector<int>& const_vect() const {
        return v;
    }
};

class ConstData : public AbstractData {
    const vector<int>& v;
    vector<int> temp;
public:
    ConstData(const vector<int>& _v) : v(_v) {}
protected:
    vector<int>& vect() const {
        return temp; // You can choose to throw an exception instead
    }
    const vector<int>& const_vect() const {
        return v;
    }
};

Note that this class hierarchy may need a destructor and various copy constructors, depending on the usage.

OTHER TIPS

The error you got was along the lines of:

foo.cpp: In constructor ‘Data::Data(const std::vector<int>&)’:
foo.cpp:8:44: error: invalid initialization of reference of type ‘std::vector<int>&’ from expression of type ‘const std::vector<int>’

...because you are trying to create a non-const reference to data that you (Data) promised your caller would be treated as const.

Here is a solution which declares a const reference as Data's member:

#include <vector>

class Data
{
    const std::vector<int> &v;
public:
    Data(std::vector<int>& _v) : v(_v) {}
    Data(const std::vector<int>& _v) : v(_v) {} // error!
};

int main()
{
    std::vector<int> v;
    std::vector<int> c_v;
    Data d(v);
    Data const_d(c_v);

    return 0;
}

Another option is to use a non-reference member instead:

#include <vector>

class Data
{
    std::vector<int> v;
public:
    Data(std::vector<int>& _v) : v(_v) {}
    Data(const std::vector<int>& _v) : v(_v) {} // error!
};
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top