By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,156 Members | 1,037 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,156 IT Pros & Developers. It's quick & easy.

Cannot write 0 for pointer in a vector.

P: n/a
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
Feb 4 '06 #1
Share this Question
Share on Google+
11 Replies


P: n/a
* 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).

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?
Feb 4 '06 #2

P: n/a

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

Feb 6 '06 #3

P: n/a

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.

Feb 6 '06 #4

P: n/a

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).

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).


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.

Feb 6 '06 #5

P: n/a

<da********@warpmail.net> skrev i meddelandet
news:11**********************@g14g2000cwa.googlegr oups.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

Feb 6 '06 #6

P: n/a
Chris Dams <ch****@wn5.nospamplease.nl> wrote:
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?


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/wg...fects.html#438

--
Marcus Kwok
Feb 6 '06 #7

P: n/a

Bo Persson wrote:
<da********@warpmail.net> skrev i meddelandet
news:11**********************@g14g2000cwa.googlegr oups.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)

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)

Feb 7 '06 #8

P: n/a
* Mi*************@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).

--
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?
Feb 7 '06 #9

P: n/a
* da********@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.

--
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?
Feb 7 '06 #10

P: n/a
On 2006-02-07 01:40:23 -0500, da********@warpmail.net said:
Bo Persson wrote:
<da********@warpmail.net> skrev i meddelandet
news:11**********************@g14g2000cwa.googlegr oups.com...

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)


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?


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
cl*******@gmail.com

Feb 7 '06 #11

P: n/a

Clark S. Cox III wrote:
On 2006-02-07 01:40:23 -0500, da********@warpmail.net said:
Bo Persson wrote:
<da********@warpmail.net> skrev i meddelandet
news:11**********************@g14g2000cwa.googlegr oups.com...

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)


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?


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?


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

Feb 8 '06 #12

This discussion thread is closed

Replies have been disabled for this discussion.