The type vector<char *>
is not convertible to const vector<const char*>
. For example, the following gives a compilation error:
#include <vector>
using namespace std;
void fn(const vector<const char*> cvcc)
{
}
int main()
{
vector<char *> vc = vector<char *>();
fn(vc);
}
I understand why vector<char*>
is not convertable to vector<const char*>
- extra members of type const char *
may be added to the vector, and afterwards they would be accessible as non-const. However, if the vector itself is const, this can't happen.
My best guess is that this would be harmless, but there is no way the compiler is allowed to deduce that this would be harmless.
How can this be worked around?
This question was suggested by the C++ FQA here.
You can't put items into a const vector, the vectors state is the items it holds, and adding items to the vector modifies that state. If you want to append to a vector you must take in a non const ref. Show activity on this post. If you have a const vector it means you can only read the elements from that vector.
A pointer to a const value (sometimes called a pointer to const for short) is a (non-const) pointer that points to a constant value. In the above example, ptr points to a const int . Because the data type being pointed to is const, the value being pointed to can't be changed. We can also make a pointer itself constant.
A pointer to constant is a pointer through which the value of the variable that the pointer points cannot be changed. The address of these pointers can be changed, but the value of the variable that the pointer points cannot be changed.
A const vector will return a const reference to its elements via the [] operator . In the first case, you cannot change the value of a const int&. In the second case, you cannot change the value of a reference to a constant pointer, but you can change the value the pointer is pointed to.
In general, C++ does not allow you to cast someclass<T>
to someclass<U>
as a template someclass
might be specialized for U
. It doesn't matter how T
and U
are related. This mean that the implementation and thus the object layout might be different.
Sadly, there is no way to tell the compiler in which cases the layout and/or behaviour didn't change and the cast should be accepted. I imagine it could be very useful for std::shared_ptr
and other use-cases, but that is not going to happen anytime soon (AFAIK).
void fn(const vector<const char*>)
As the top-level const
qualifier is dropped for the function type, this is (at the call site) equivalent to:
void fn(vector<const char*>)
Both of which request a copy of the passed vector, because Standard Library containers follow value semantics.
You can either:
fn({vc.begin(), vc.end()})
, requesting an explicit conversionvoid fn(vector<const char*> const&)
, i.e. taking a referenceIf you can modify the signature of fn
, you can follow GManNickG's advice and use iterators / a range instead:
#include <iostream>
template<typename ConstRaIt>
void fn(ConstRaIt begin, ConstRaIt end)
{
for(; begin != end; ++begin)
{
std::cout << *begin << std::endl;
}
}
#include <vector>
int main()
{
char arr[] = "hello world";
std::vector<char *> vc;
for(char& c : arr) vc.push_back(&c);
fn(begin(vc), end(vc));
}
This gives the beautiful output
hello world ello world llo world lo world o world world world orld rld ld d
The fundamental issue is to pass around Standard Library containers. If you only need constant access to the data, you don't need to know the actual container type and can use the template instead. This removes the coupling of fn
to the type of container the caller uses.
As you have noticed, it's a bad idea to allow access of a std::vector<T*>
through a std::vector<const T*>&
. But if you don't need to modify the container, you can use a range instead.
If the function fn
shall not or cannot be a template, you could still pass around ranges of const char*
instead of vectors of const char
. This will work with any container that guarantees contiguous storage, such as raw arrays, std::array
s, std::vector
s and std::string
s.
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