Explicitly initializing vector of pointers results in conversion error?

Go To StackoverFlow.com

9

Consider this:

std::vector<int*> v(1, 0);

This compiles fine with VC++10 (no warnings even at max warning level). However, it doesn't compile with llvm on mac or gcc on linux, giving an error like "assigning to int* from incompatible type const int." I'm not looking for solutions -- I know the second parameter is unnecessary or that a static_cast fixes the error.

I thought zero was implicitly convertible to any pointer type. What gives? I can do the following:

int* i = 0;
int* const& ii = 0;
const int t = 0;
i = t;

I understand that the vector constructor signature takes a const T& which when expanded for vector<int*> becomes int* const& correct? Can someone explain what is going on here, and whether the VC++ or non-VC++ compiler is correct?

2012-04-04 19:03
by Tabber33
Try nullptr instead of 0 - ildjarn 2012-04-04 19:06
Are you compiling this as a C++03 or a C++11 program - Robᵩ 2012-04-04 19:06
Not related to question, but, why are you using raw pointers when Bjarne said we should avoid them - dario_ramos 2012-04-04 19:10
This looks like a compiler bug to me - dasblinkenlight 2012-04-04 19:10
I know, it's a long video. The part about not using raw pointers is at 43:00 - dario_ramos 2012-04-04 19:16
@dario_ramos: You shouldn't use raw pointers when you need ownership semantics, but it's fine to use them when you really just want to point at something - GManNickG 2012-04-04 19:19
@GManNickG: In those cases, you should use references - dario_ramos 2012-04-04 19:21
@dario_ramos: Not if I want to optionally point to things, or change what I'm pointing at - GManNickG 2012-04-04 19:22
@GManNickG: And that's when thing start to get messy/dangerous... Oh well, let's agree to disagree - dario_ramos 2012-04-04 19:23
@dario_ramos: Let's not. You can't come in, say a bunch of stuff, then end with, "well now it's all to messy to talk about, we're just going to agree to disagree." There's nothing messy or dangerous about pointing to something. The reason people like Bjarne are hesitant to make statements like he did is because people such as yourself will come in and say, "didn't you hear? A single person who I think has complete authority utters some words, so they must never be false!" Bjarne is very specifically talking about using pointers in memory management. This is old stuff - GManNickG 2012-04-04 19:29
thanks guys -- this is why I love stackoverflow. this was an academic question involving the porting of legacy code which i already found a solution to. i'm well aware of modern c++ usage with repect to memory management, but thanks for the entertaining and pointless banter - Tabber33 2012-04-04 19:43


2

It looks like g++ actually wrong here. See C++98 23.1.1/9:

For every sequence defined in this clause and in clause 21:

— the constructor template X(InputIterator f, InputIterator l, const Allocator& a = Allocator())

shall have the same effect as: X(static_cast<typename X::size_type>(f), static_cast<typename X::value_type>(l), a) if InputIterator is an integral type.

Note that InputIterator is a template parameter to the constructor, which in this case will be int for your example, and thus an integral type. The g++ library actually has specific code to handle all the cases where the type being stored in the vector is integral as well and those will all work properly. In this case, only because you used 0 would the static_cast dictated by the standard actually be legal. I tried compiling the code that the standard says should be equivalent and it compiles with g++ 4.5.

2012-04-04 20:12
by Mark B
good work. std::vector<int> v(1, 0); compiles just fine. i didn't expect MS to be correct here - Tabber33 2012-04-04 20:41
It depends on whether the implementation has considered Library Issue #438 which says that this doesn't work. The suggested solution is X(static_cast<typename X::size_type>(f), l, a) which matches Tabber's failure. C++11 instead followed Defect Report #1234 with, again, a different result - Bo Persson 2012-04-04 21:45


2

std::vector has a nasty constructor with this signature

template <class InputIterator>
vector(InputIterator first, InputIterator last,
       const Allocator& = Allocator());

which, if the compiler deducts InputIterator as int(!) from your parameters 0 and 1, will be a good fit but not do what we want.

I believe C++11 requires the compiler to try harder to figure out if the parameters could actually be iterators or not. In C++03 they would probably end up as size_type(1) and int(0), causing your problem.

The integer literal 0 is convertible to a null pointer, but an int with value 0 is not!

2012-04-04 19:14
by Bo Persson
thank you. you are correct -- looking at the errors more closely, i now see that the instantiation of the templated constructor was at the root of the error tree. i only wonder now why VC++ (even pre-c++11 support) goes to the extra "trouble" to call the intended constructor here, and violates language rules to do so (after all, the templatized constructor is a better match) - Tabber33 2012-04-04 19:47
@Bo Persson If I'm reading 23.1.1/9 correctly, this is not the right answer: g++ actually missed a special case - Mark B 2012-04-04 20:13
Ads