1

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

12
  • Can you post a minimal reproducible example as usual please. Commented Oct 13, 2016 at 21:39
  • @Jarod42 nullptr edited out as it has nothing to do with the question. Commented Oct 13, 2016 at 21:41
  • NULL is 0, and doesn't have pointer type and is deduced as integer type, thus the error. Commented Oct 13, 2016 at 21:42
  • Because I'm tired. Deleting. Commented Oct 13, 2016 at 21:43
  • 1
    static_cast<int*>(NULL) is suitable, yes Commented Oct 13, 2016 at 21:45

2 Answers 2

6

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.

Sign up to request clarification or add additional context in comments.

2 Comments

nullptr is not in the C++03 standard. So this is not a viable solution. I did add it as a tag on the question because I knew it to be the C++11 solution to this problem.
@JonathanMee: I suspected. Use a C++03 implementation of it, then. See section 1.1 of open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf (which is just an excerpt from Scott Meyers' Effective C++).
0

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) and f(char*), the call f(0) unambiguously resolves to f(int). There is no way to write a call to f(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:

  1. An explicit cast
  2. 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.

8 Comments

Sorry to be dense, but what does this add that my answer doesn't already have?
@GManNickG 1)Proof that nullptr is not available in C++03 2)Definition of the options available in C++03 3)Consideration for the best C++03 alternative to nullptr 4)The definitive C++03 cross platform solution
...so I repeat. My answer already states nullptr is not in C++03, and suggests alternatives for C++03 (including the cast solution as well). Neither is the "best" or "definitive", but whatever floats your boat I guess.
@GManNickG To quote a few lines where your answer recommends implementation defined behaviors over a standard condoned behavior: "tl;dr: Use nullptr" and "There are various C++03 implementations of nullptr if you need one." If the question hadn't been tagged C++03 your answer would be correct, unfortunately it leads readers to believe that the solution the standard does offer, should be used "in a pinch". I find this misleading. Since the standard floats the C++03 boat I'm going to go with the answer that presents standard defined C++03 options.
Huh? Nothing about that is implementation-defined. You can write a class, with well-defined behavior, and use it in place of nullptr. Is writing classes no longer C++03 standard?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.