Reputation: 1231
I was recently coding a very simple class
, which is responsible for finding the min and max values in a std::vector
and found out, that even when I pass the collection as a const reference
to the class
' constructor and then change the vector (ie. push an element into it or remove one from it) from outside, the vector inside the class
remains unchanged.
#include <vector>
#include <algorithm>
class MinMaxFinder
{
public:
MinMaxFinder(const std::vector<int>& numbers) : numbers(numbers)
{
}
const int Min() const
{
this->findMinAndMax();
return this->min;
}
const int Max() const
{
this->findMinAndMax();
return this->max;
}
protected:
std::vector<int> numbers;
int min;
int max;
void findMinAndMax()
{
// std::minmax_element call to find min and max values
}
};
I assumed the point of passing a reference is so that a large object is not copied, the way my code works now, however, seems like it does copy the collection.
#include <vector>
#include <iostream>
#include "MinMaxFinder.h"
int main(int argc, char* argv[])
{
std::vector<int> v{ 1, -6, 12, 158, -326 };
MinMaxFinder mmf(v);
v.push_back(-9999999);
v.push_back(9999999);
auto min = mmf.Min();
auto max = mmf.Max();
}
The value of min
will be -326
, the value of max
will be 158
, even though it is pretty clear that the value 9999999
is much larger than 158
.
I managed to fix this behaviour by changing the definition of the private member numbers
to std::vector<int>& numbers
, but is it the correct solution?
Still, why would the state of internal collection remain unchaged, does it not defy the definition of passing by const ref?
Upvotes: 1
Views: 145
Reputation: 234785
The member initialisation numbers(numbers)
called on construction will take a deep copy.
If you were to compute the minimum and maximum values on construction, then you wouldn't need to retain numbers
as a class member.
You could store a reference as the class member, but then you'd have to be careful to limit the lifetime of your class instance to that where the vector is in scope, else the reference could dangle. I'd advise against doing that.
Upvotes: 3
Reputation: 26506
std::vector<int> numbers;
should be const std::vector<int>& numbers;
this way you reference an object without copy it or having the ability of changing it.
but seriously, what is the point of this class? huge overkill! just use std::min_element
and std::max_element
or std::minmax_element
..
auto minimun = std::min_element(numbers.begin(),numbers.end());
Upvotes: 6
Reputation: 172964
The member varialbe numbers
is not declared as reference, so it will be copied when get initialized, even though the ctor's parameter is passed by reference. Try to change the declaration to:
protected:
const std::vector<int>& numbers;
Upvotes: 0
Reputation: 385274
I assumed the point of passing a reference is so that a large object is not copied
Yeah, that's right, and the large object isn't copied when "calling" the constructor.
However, your data member is a value, not a reference, so the argument is immediately copied to initialise the member.
It's like writing this:
std::vector<int> v;
const std::vector<int>& ref = v;
std::vector<int> v2 = ref;
then wondering why v2
is a copy. :)
Upvotes: 3