Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Cannot write 0 for pointer in a vector.

1 view
Skip to first unread message

Chris Dams

unread,
Feb 4, 2006, 3:13:11 PM2/4/06
to
Dear all,

I found out that the program

#include<vector>

using namespace std;

int main()
{ vector<int*> v(2,0);
return 0;
}

does not compile using g++ 4.0.2. It says (including quite a of STL-error
message): "error: invalid conversion from error: invalid conversion from
const int to int*". This made me try to replace v(2,0) by v(2,NULL) and now
it compiles.

However, I seem to vaguely remember that NULL should be #defined to be 0
in C++, so why this error? Is the a compiler wrong to complain about this?

Best,
Chris

Alf P. Steinbach

unread,
Feb 4, 2006, 3:47:06 PM2/4/06
to
* Chris Dams:

What you're up against is the selection of the templated constructor
with two iterators, instead of the constructor with a size and a default
value (I _think_ that's because the default value is passed by reference
to const, but someone correct me if that's not the case).

Paragraph 23.1.1/9 defines the effect of the templated constructor

template< class Iter >
X( Iter first, Iter last, Allocator const& a = Allocator() )

as

X(
static_cast<typename X::size_type>( first ),
static_cast<typename X::value_type>( last ),
a
)

when Iter is an integral type, as it is in your case.

However a natural reading is that this applies to the implementation,
not as a client code transformation, and in the implementation the
compile time 0 has been transformed to a run time argument of type
'int', which cannot be casted to 'int*'.

Summing up, the compiler seems to be correct for the case of literal 0,
and for the case of NULL it might be that with this compiler NULL is
defined as 0L (for example), which it's allowed to be, and then the two
arguments are not of the same type, and the template constructor is not
selected, which if that's the case would mean the compiler is correct.

And which, if my analysis is correct, means that this almost trivial
little piece of code has Undefined Behavior (different compilers can
then freely elect to accept or reject the NULL case, depending on the
definition of NULL).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?

Michiel...@tomtom.com

unread,
Feb 6, 2006, 9:51:53 AM2/6/06
to

Alf P. Steinbach wrote:
> * Chris Dams:
> >
> > I found out that the program
> >
> > #include<vector>
> >
> > using namespace std;
> >
> > int main()
> > { vector<int*> v(2,0);
> > return 0;
> > }
> >
> > does not compile using g++ 4.0.2. It says (including quite a of STL-error
> > message): "error: invalid conversion from error: invalid conversion from
> > const int to int*". This made me try to replace v(2,0) by v(2,NULL) and now
> > it compiles.
> >
> > However, I seem to vaguely remember that NULL should be #defined to be 0
> > in C++, so why this error? Is the a compiler wrong to complain about this?
>
> What you're up against is the selection of the templated constructor
> with two iterators, instead of the constructor with a size and a default
> value (I _think_ that's because the default value is passed by reference
> to const, but someone correct me if that's not the case).

No, the iterator version is simply a better match by the normal
overload rules.
NULL is not an object of type T*, even though it can be converted to
one.
On the other hand, the iterator version has no conversions but requires
only a template instantiation.

...


> Summing up, the compiler seems to be correct for the case of literal 0,
> and for the case of NULL it might be that with this compiler NULL is
> defined as 0L (for example), which it's allowed to be, and then the two
> arguments are not of the same type, and the template constructor is not
> selected, which if that's the case would mean the compiler is correct.
>
> And which, if my analysis is correct, means that this almost trivial
> little piece of code has Undefined Behavior (different compilers can
> then freely elect to accept or reject the NULL case, depending on the
> definition of NULL).

That would be unspecified behavior. Undefined includes lots of bad
things.
Unspecified means they can only accept or reject it, without
documenting
how the choice is made. However, if they accept it, the behavior is
still
bound by the requirements of the standard.

HTH,
Michiel Salters

robert...@gmail.com

unread,
Feb 6, 2006, 9:57:22 AM2/6/06
to

Alf P. Steinbach wrote:

> And which, if my analysis is correct, means that this almost trivial
> little piece of code has Undefined Behavior (different compilers can
> then freely elect to accept or reject the NULL case, depending on the
> definition of NULL).

VC++ 2005 rejects it but accepts 0L for the second argument.

david...@warpmail.net

unread,
Feb 6, 2006, 11:23:40 AM2/6/06
to

As far as I know, the implementation is required to distinguish the
case where both arguments are integral types from the iterator case.
Sounds like the g++ STL implementation has a bug.

Bo Persson

unread,
Feb 6, 2006, 12:37:05 PM2/6/06
to

<david...@warpmail.net> skrev i meddelandet
news:1139243020.5...@g14g2000cwa.googlegroups.com...

>
> Alf P. Steinbach wrote:
>>
>> Summing up, the compiler seems to be correct for the case of
>> literal 0,
>> and for the case of NULL it might be that with this compiler NULL
>> is
>> defined as 0L (for example), which it's allowed to be, and then the
>> two
>> arguments are not of the same type, and the template constructor is
>> not
>> selected, which if that's the case would mean the compiler is
>> correct.
>>
>> And which, if my analysis is correct, means that this almost
>> trivial
>> little piece of code has Undefined Behavior (different compilers
>> can
>> then freely elect to accept or reject the NULL case, depending on
>> the
>> definition of NULL).
>
> As far as I know, the implementation is required to distinguish the
> case where both arguments are integral types from the iterator case.
> Sounds like the g++ STL implementation has a bug.
>

No, I believe it is correct. This is a corner case.

There are three possible constructors to choose from

the regular
vector(size_type, value_type)
and the template instantiations
vector(int, int)
vector(Iterator, Iterator)

Now, which one is the best for vector(2, 0) ?

Obviously, 2 and 0 are not iterators, so that one is ruled out.

For vector(size_type, value_type), size_type is unsigned, but the
constant 2 isn't. So it's not the best match.

So, we now have vector(int, int) as a candidate. vector(2, 0) matches
perfectly, so this is the best match.

Unfortunately, we have now determined that the 0 must be of type int,
which then cannot be converted to an int* !

Any (ANY!) change to the type of one of the parameters, will rule out
the vector(int, int) constructor, thereby making the vector(size_type,
value_type) a candidate. Try vector(2u, 0) for instance!


Bo Persson

Marcus Kwok

unread,
Feb 6, 2006, 4:50:58 PM2/6/06
to

I'm not sure if this same issue applies to you since you're talking
about int*'s instead of int's, but there is a defect report for
statements of the form:

vector<int> v(10, 1);

binding to the vector(InputIterator, InputIterator) form instead of the
vector(size_type, const value_type&) form.

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#438

--
Marcus Kwok

david...@warpmail.net

unread,
Feb 7, 2006, 1:40:23 AM2/7/06
to


I'm a little lost here. There are only four constructors for 'vector':

explicit vector(const Allocator& = Allocator());
explicit vector(size_type n, const T& value = T(),
const Allocator& = Allocator());
template <class InputIterator>
vector(InputIterator first, InputIterator last,
const Allocator& = Allocator());
vector(const vector<T,Allocator>& x);

Of these four, we consider only the middle two, which take two
non-allocator arguments. In this case, the template type argument is
'int*', so the choices are

explicit vector(size_t, const int*&) // default allocator, not
shown

template <class InputIterator>
vector(InputIterator first, InputIterator last)

Where do you get

vector(int, int)

from? My understanding is that the InputIterator template should be
prevented from resolving to

vector(int, int)

Alf P. Steinbach

unread,
Feb 7, 2006, 2:05:07 AM2/7/06
to
* Michiel...@tomtom.com:
> * Alf P. Steinbach:

> >
> > And which, if my analysis is correct, means that this almost trivial
> > little piece of code has Undefined Behavior (different compilers can
> > then freely elect to accept or reject the NULL case, depending on the
> > definition of NULL).
>
> That would be unspecified behavior. Undefined includes lots of bad
> things.
> Unspecified means they can only accept or reject it, without
> documenting how the choice is made.

I think that's wrong, since unspecified is for "a well-formed program
construct and correct data". Something that doesn't compile doesn't
seem to me to meet those requirements. So as I see it it's unspecified,
and then -- yes, there are then no guarantees whatsoever...


PS: Thanks for clarifying/correcting my muddled thinking about the why
of the binding (not quoted above).

Alf P. Steinbach

unread,
Feb 7, 2006, 2:10:43 AM2/7/06
to
* david...@warpmail.net:
> * Alf P. Steinbach:

> >
> > Paragraph 23.1.1/9 defines the effect of the templated constructor
> >
> > template< class Iter >
> > X( Iter first, Iter last, Allocator const& a = Allocator() )
> >
> > as
> >
> > X(
> > static_cast<typename X::size_type>( first ),
> > static_cast<typename X::value_type>( last ),
> > a
> > )
> >
> > when Iter is an integral type, as it is in your case.
>
> As far as I know, the implementation is required to distinguish the
> case where both arguments are integral types from the iterator case.
> Sounds like the g++ STL implementation has a bug.

No, it's as I wrote above and you quoted (did you miss it?): the case
that's distinguished is when Iter is an integral type, not when both
arguments are of possibly different integral types.

Clark S. Cox III

unread,
Feb 7, 2006, 11:33:10 AM2/7/06
to
On 2006-02-07 01:40:23 -0500, david...@warpmail.net said:
> Bo Persson wrote:
>> <david...@warpmail.net> skrev i meddelandet
>> news:1139243020.5...@g14g2000cwa.googlegroups.com...
>>>

Instantiating "template <class InputIterator> vector(InputIterator
first, InputIterator last)" with "InputIterator" = "int"

> My understanding is that the InputIterator template should be
> prevented from resolving to
>
> vector(int, int)

Why do you think that?

Try this:

#include <iostream>

class Foo
{
public:
Foo() { std::cout << "Foo() called\n"; }
Foo(size_t, int*) { std::cout << "Foo(size_t, int*) called\n"; }
template<typename InputIterator>
Foo(InputIterator, InputIterator) { std::cout << "Foo(InputIterator,
InputIterator) called\n"; }
};

int main()
{
Foo foo(5,0);
return 0;
}

--
Clark S. Cox, III
clar...@gmail.com

david...@warpmail.net

unread,
Feb 7, 2006, 11:31:17 PM2/7/06
to

Yes, I was mistaken. However, I do not believe that the case in point
here is allowed to be undefined.

0 new messages