std::equal not working when using vectors returned by a getter

While learning about how std::equal works, I was writing some test code and ran into this problem:

#include <iostream>
#include <vector>
#include <algorithm>

class Foo {

public:
    std::vector<int> vec;

    Foo(std::vector<int> _vec) {
        vec = _vec;
    }

    std::vector<int> get() {
        return vec;
    }

};

int main() {
    
    std::vector<int> x{ 1, 2, 3, 4, 5 };
    std::vector<int> y{ 1, 2, 3, 4, 5 };

    Foo a = Foo(x);
    Foo b = Foo(y);

    std::cout << std::equal(a.vec.begin(), a.vec.end(), b.vec.begin()) << "\n";
    // Outputs: 1

    std::cout << std::equal(a.get().begin(), a.get().end(), b.get().begin()) << "\n";
    // Outputs: 0 <-- why?

    std::cout << (a.get() == b.get());
    // Outputs: 1
}

When I compare two vectors that are returned by the getter function, they are not equal. Why is this?

I understand that if I return by reference in the method std::vector<int>& get, it’ll print that the vectors are equal. However, I might need to use this getter method in a function that takes in a const Foo& argument. However, returning by reference isn’t allowed in a const function (std::vector<int>& get() const is not allowed).


For my practical purpose, I will need to check that two vectors of doubles are equal by checking if each corresponding element’s difference falls within a certain tolerance range. It looks something like this:

bool is_equal(double val1, double val2) {
    return abs(val1 - val2) < 0.0001;
}

Given 2 Foo objects a and b, I want to check if their vectors are equal (vec is private):

std::equal(a.get().begin(), a.get().end(), b.get().begin(), is_equal); // This won't work

For this reason I can’t really use a.get() == b.get() (I would if I could) because rounding inaccuracies might give unwanted results.

Any insight on what’s going on and what I can do? Thanks!

>Solution :

First, return by const reference

const std::vector<int>& get() const {
    return vec;
}

that solves the problem. An alternative would be to have two getters returning the begin and end iterator, instead of returning the vector itself.

Second, the reason for the problem is that your version of the getter copies the vector. so in

std::equal(a.get().begin(), a.get().end(), b.get().begin())

your iterators a.get().begin() and a.get().end() are pointing at two different vectors (both copies of the vector in the class).

Leave a Reply