Say I have this class:
#include <vector>
using namespace std;
class Bag
{
vector<int*> items;
public:
void addItem(int* i)
{
items.push_back(i);
}
const vector<int*> getItems() const
{
return items;
}
};
The problem is I want to prevent changes of the values pointed by the pointers in parameter items. But using the vector returning from getItems
I'm allowed to change the pointed values.
Now, in order to fix that I can declare the parameter items as vector<const int*>
but then I can't change the values in my class either.
Is there any other way to protect the values but still not using const in the items declarations?
As @KerrekSB pointed out, you need to reconstruct the structure, changing the type of the element to a const one:
std::vector<const int*> getItems() const {
return std::vector<const int*>(items.begin(), items.end());
}
Here the constructor of vector<const int*>
utilizes the implicit conversion from int*
to const int*
. You can't just return items
here, because vector<T>
is invariant on T. This directly means that there's no way to convert from vector<int*>
to vector<const int*>
just by a type cast.
To address your comment:
Is this the only way? I feel like creating a copy is inefficient.
As for the copy, it copies only the pointer data, so typically 8 bytes per element. For a vector of pointers to larger structures, it's typically negligible, but for a vector of int
s it indeed is a rather large overhead.
Which brings us to the question: why are you storing pointers in the first place? Simply store vector<int>
, and then you can just return a const&
to it.
If you want to avoid copies and allow read-only access to your std::vector
elements, you could instead provide functions to get a const_iterator
into the container:
class Bag
{
vector<int*> items;
public:
void addItem(int* i)
{
items.push_back(i);
}
//could just be called begin if that gives the correct idea
vector<int*>::const_iterator itemsBegin() const
{
return std::cbegin(items);
}
vector<int*>::const_iterator itemsEnd() const
{
return std::cend(items);
}
};
Then you would loop over the Bag
contents using that iterator rather than getting out a whole vector
of items. If you provided begin
and end
functions then you could even use range-based for-loops.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With