Home > front end >  how to have a class variable reference an external object
how to have a class variable reference an external object

Time:09-10

I have the following piece of code

https://godbolt.org/z/n6doeTfGa

#include <vector>
#include <iostream>

class mainClass
{
    public:
    mainClass(std::vector<int>& outvect) : m_vec(outvect)
    {}
    auto iterate() -> void
    {
        for (auto& elem : m_vec)
            std::cout << elem << std::endl;
    }
    private:
    std::vector<int> m_vec;
};


int main()
{
    std::vector<int> v{1,2,3};
    auto classObj = mainClass(v);
    v.push_back(4);
    classObj.iterate();
}

Now the program just prints 1,2,3. But I would like for it also print all the change that happen to v.

I was able to come up with this solution.

https://godbolt.org/z/ca4xrhxeE

#include <vector>
#include <iostream>

class mainClass
{
    public:
    mainClass(std::vector<int>& outvect) : m_vec(&outvect)
    {}
    auto iterate() -> void
    {
        for (auto& elem : *m_vec)
            std::cout << elem << std::endl;
    }
    private:
    std::vector<int>* m_vec;
};


int main()
{
    std::vector<int> v{1,2,3};
    auto classObj = mainClass(v);
    v.push_back(4);
    classObj.iterate();
}

But is there a cleaner way to do this without using pointers?

CodePudding user response:

Just use references:

#include <vector>
#include <iostream>

class mainClass
{
    public:
    mainClass(std::vector<int>& outvect) : m_vec(outvect)
    {}
    auto iterate() -> void
    {
        for (auto& elem : m_vec)
            std::cout << elem << std::endl;
    }
    private:
    std::vector<int>& m_vec;
};


int main()
{
    std::vector<int> v{1,2,3};
    auto classObj = mainClass(v);
    v.push_back(4);
    classObj.iterate();
}

CodePudding user response:

As you are asking for a "clean" way, this is what I would prefer:

#include <vector>
#include <iostream>

auto iterate(auto m_vec) {
    for (auto& elem : m_vec)
        std::cout << elem << std::endl;
}

int main() {
    std::vector<int> v{1,2,3};
    v.push_back(4);
    iterate(v);
}

Reference members have some unpleasant implications (eg no copies) that are usually unwanted for anything but short-lived helper/wrapper objects. Using a pointer member opens another can of worms: ownership. Who owns the vector? Who makes sure that the vector is still alive when iterate is using it? Smart pointers can help with that. Though as there is no state in your class (other than the reference to the vector which is supposed to be managed outside of the class) I see no reason to write a class.

You can bind a reference to the vector to the free function via a lambda expression:

int main() {        
    std::vector<int> v{1,2,3};
    auto iterator = [&](){ iterate(v); };
    v.push_back(4);
    iterator();
}

With a lambda it is a little more obvious that it captures by reference and can only be used as long as the vector is alive. By using the lambda you also avoid all headaces mentioned above that come with raw pointer or reference member of self written class.

  •  Tags:  
  • c
  • Related