Search code examples
c++initializationinitializer-listconst-reference

How to initialize a const reference member to another member (std vector) in C++ initializer list


I did the following as a cheap way to allow read-only access to a member container _numbers via numbers:

class Foo {
    Foo() : _numbers({}), numbers(_numbers) {
    // some code that populates `numbers` via `numbers.push_back(...)`
}

private:
    std::vector<int> _numbers;
public:
    const std::vector<int>& numbers;
}

However, doing so I see that numbers is empty, while in other cases it will contain the same elements as _numbers.

To be more precise, it seems to be undefined behavior. In my real example (of which this a simplified version) I have multiple reference-container pairs with this scheme, where the populated data is visible in the const-reference member for some pairs, and for some it is not.

Any idea whats wrong with this? Any help is deeply appreciated.

EDIT Here is a minimal working example:

#include <vector>

struct Foo2 {
public:
     const int max1;
     const int center1;

    Foo2(const int max1_);
private:
    std::vector<int> _numbers1, _numbers2;

public:
    const std::vector<int>& numbers1, numbers2;
};

Foo2::Foo2(const int max1_)
    : max1(max1_), center1(max1_/2),
      _numbers1({}), _numbers2({}),
      numbers1(_numbers1),
      numbers2(_numbers2)
{
    cout << max1 << endl;

    for (int i=0; i<center1; i++) {
        _numbers1.push_back(i);
        cout << "A: " << i << endl;
    }
    for (int i=center1; i<max1; i++) {
        _numbers2.push_back(i);
        cout << "B: " << i << endl;
    }

    for (int i: numbers1) {
        cout << "A: " << i << endl;
    }
    for (int i: numbers2) {
        cout << "B: " << i << endl;
    }
}

which gives the following Output when initializing Foo2 f(8):

8
A: 0
A: 1
A: 2
A: 3
B: 4
B: 5
B: 6
B: 7
A: 0
A: 1
A: 2
A: 3

i.e. numbers2 does not see the contents of _numbers2 while for numbers1 it seems to work.


Solution

  • const vector<int>& numbers1, numbers2; — Here, only the first variable is a reference. You need & before the second variable to make it a reference as well. Then the code should work.

    But I have to say that what you're doing is a really bad idea. You're paying for a convenient syntax with memory overhead, non-assignability, and possibly speed overhead.

    Use getters instead: const vector<int>& numbers1() const {return _numbers1;}. Yes, you will have to type the extra () every time.