问题
I have int* foo[SIZE]
and I want to search it for the first element that points to NULL
.
But when I do this:
std::find(foo, foo + SIZE, NULL)
I get the error:
error C2446: '==' : no conversion from 'const int' to 'int *'
Should I just be using static_cast<int*>(NULL)
instead of NULL
?
C++11 solves this via nullptr but that's not an option for me in C++03
回答1:
tl;dr: Use nullptr
, or define your own equivalent.
The problem is that NULL
is some macro that expands to an integral constant expression with value zero. In order to call the function, std::find
has to deduce the type and use the value (0
).
You cannot compare int*
with int
, hence the error. As far as the function is concerned, you just passed it some regular old int
that happens to be zero, and those cannot be converted to null pointers; they have to be integral constant expressions.
Normally NULL
"works" because it's used in contexts where it isn't treated just as its integer form, e.g.:
if (ptr == NULL)
Because here it maintains its "integral constant expression" status, so converts to a null pointer of the compared-to type.
You should use nullptr
if you're in C++11 or beyond, because this is actually a null pointer, not an integer that converts to it. What you've described is actually one of the motivating factors for introducing nullptr
.
There are various C++03 implementations of nullptr
if you need one. I have attached the classic implementation at the bottom of this answer.
Also, you should prefer std::array
if possible (Boost has one if you need it), or at the very least use std::begin
and std::end
to get the array begin and end pointers (and again, there are implementations of this floating around):
#include <algorithm>
#include <array>
int main() {
std::array<int*, 8> foo = {};
std::find(foo.begin(), foo.end(), nullptr);
}
All said, in a pinch casting to the null pointer of your type is a valid solution. nullptr
is really just a short-hand for "a thing that converts to the null pointer of the needed type".
Here is a nullptr
implementation, initially created by Scott Meyers:
const
struct nullptr_t {
template <typename T>
operator T*() const {
return 0;
}
template <typename C, typename T>
operator T C::*() const {
return 0;
}
private:
void operator&() const;
} nullptr = {};
The syntax looks a bit funny because we don't usually define a class and a variable at the same time. Obviously if you want to stay C++11 compatible, nullptr
isn't a usable identifier. null_ptr
or nullpointer
are good alternatives.
回答2:
This problem is actually called out in Herb Sutter and Bjarne Stroustrup's: A name for the null pointer: nullptr:
Distinguishing between null and zero. The null pointer and an integer 0 cannot be distinguished well for overload resolution. For example, given two overloaded functions
f(int)
andf(char*)
, the callf(0)
unambiguously resolves tof(int)
. There is no way to write a call tof(char*)
with a null pointer value without writing an explicit cast (i.e.,f((char*)0)
) or using a named variable
So we see that this problem can be solved by either:
- An explicit cast
- The declaration of a value with matching type, for example:
const int* piNULL = NULL
Ideally when using the explicit cast a C-Style cast can be avoided. Either of these C++-Style casts effectively returns an int*
containing address NULL
:
reinterpret_cast<int*>(NULL)
static_cast<int*>(NULL)
http://en.cppreference.com/w/cpp/types/NULL asserts that:
A null pointer constant may be implicitly converted to any pointer type; such conversion results in the null pointer value of that type
And since static_cast:
Converts between types using a combination of implicit and user-defined conversions
static_cast
more closely defines the type of cast intended than does reinterpret_cast which:
Converts between types by reinterpreting the underlying bit pattern
So, in C++03 static_cast<int*>(NULL)
is the tightest inline definition of C++11's nullptr
that can be achieved.
来源:https://stackoverflow.com/questions/40031426/finding-a-pointer-to-null