2016-10-13 1 views
1

J'ai int* foo[SIZE] et je veux qu'il recherche le premier élément qui pointe vers NULL.Trouver un pointeur NULL à

Mais quand je fais ceci:

std::find(foo, foo + SIZE, NULL) 

Je reçois l'erreur:

error C2446: '==' : no conversion from 'const int' to 'int *'

devrais-je utiliser simplement static_cast<int*>(NULL) au lieu de NULL?

11 C++ résout ce problème via nullptr mais ce n'est pas une option pour moi en C++ 03

+0

Pouvez-vous poster un [MCVE] comme d'habitude s'il vous plaît. –

+0

@ Jarod42 'nullptr' édité car il n'a rien à voir avec la question. –

+0

'NULL' est' 0', et n'a pas de type pointeur et est déduit comme type entier, donc l'erreur. – Jarod42

Répondre

0

Ce problème est en fait appelé dans Herb Sutter et Bjarne Stroustrup: 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

Nous voyons donc que ce problème peut être résolu soit par:

  1. Un casting explicite
  2. La déclaration d'une valeur avec le type correspondant, par exemple: const int* piNULL = NULL

Idéalement, lorsque vous utilisez la distribution explicite, vous pouvez éviter une distribution de type C. Chacune de ces C++ - style moulages retourne effectivement une int* contenant l'adresse NULL:

  • reinterpret_cast<int*>(NULL)
  • static_cast<int*>(NULL)

http://en.cppreference.com/w/cpp/types/NULL affirme que:

A null pointer constant may be implicitly converted to any pointer type; such conversion results in the null pointer value of that type

Et depuis static_cast:

Converts between types using a combination of implicit and user-defined conversions

static_cast plus près définit le type de fonte destinée que ne reinterpret_cast qui:

Converts between types by reinterpreting the underlying bit pattern

Ainsi, en C++ 03 static_cast<int*>(NULL) est la définition en ligne serré de 11 de nullptr C++ qui peut être réalisé.

+0

Désolé d'être dense, mais qu'est-ce que cela ajoute que ma réponse n'a pas déjà? – GManNickG

+0

@GManNickG 1) Preuve que 'nullptr' n'est pas disponible en C++ 03 2) Définition des options disponibles en C++ 03 3) Prise en compte de la meilleure alternative C++ 03 à' nullptr' 4) Le C définitif ++ 03 solution de plate-forme croisée –

+0

... donc je répète. Ma réponse dit déjà nullptr n'est pas en C++ 03, et suggère des alternatives pour C++ 03 (y compris la solution cast). Ni le «meilleur» ou le «définitif», mais tout ce qui flotte votre bateau, je suppose. – GManNickG

6

tl; dr: Utilisez nullptr, ou définir votre propre équivalent.


Le problème est que NULL est quelque macro qui se dilate à une expression constante intégrale avec la valeur zéro. Pour appeler la fonction, std::find doit déduire le type et utiliser la valeur (0). Vous ne pouvez pas comparer int* avec int, d'où l'erreur. En ce qui concerne la fonction, vous venez de lui passer un certain int ancien qui se trouve être zéro, et ceux-ci ne peuvent pas être convertis en null pointeurs; ils doivent être des expressions constantes intégrales.

Normalement NULL « fonctionne » car il est utilisé dans des contextes où il est pas considéré comme sa forme entière, par exemple:

if (ptr == NULL) 

Parce qu'ici il conserve son statut « d'expression constante intégrale », donc convertit un pointeur null du type compare-to.

Vous devez utiliser nullptr si vous êtes en C++ 11 ou au-delà, car il s'agit en fait d'un pointeur nul, pas d'un entier qui le convertit. Ce que vous avez décrit est en fait l'un des facteurs de motivation pour introduire nullptr.

Il existe plusieurs C++ 03 implémentations de nullptr si vous en avez besoin. J'ai joint l'implémentation classique au bas de cette réponse.

En outre, vous devriez préférer std::array si possible (Boost a un si vous en avez besoin), ou à tout le moins utiliser std::begin et std::end pour obtenir le tableau commence et les pointeurs de fin (et encore, il y a des mises en œuvre de ce flottant autour):

#include <algorithm> 
#include <array> 

int main() { 
    std::array<int*, 8> foo = {}; 
    std::find(foo.begin(), foo.end(), nullptr); 
} 

Tous ont dit, dans une coulée de pincement au pointeur nULL de votre type est une solution valable. nullptr est vraiment juste un raccourci pour "une chose qui convertit au pointeur nul du type nécessaire".


Voici une implémentation nullptr, initialement créé par 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 = {}; 

La syntaxe ressemble un peu drôle parce que nous ne définissons pas généralement une classe et une variable en même temps. Évidemment, si vous voulez rester compatible C++ 11, nullptr n'est pas un identifiant utilisable. null_ptr ou nullpointer sont de bonnes alternatives.

+0

'nullptr' n'est pas dans la norme C++ 03. Donc, ce n'est pas une solution viable. Je l'ai ajouté comme étiquette sur la question parce que je savais que c'était la solution C++ 11 à ce problème. –

+0

@JonathanMee: Je me doutais. Utilisez une implémentation C++ 03, alors. Voir la section 1.1 de http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf (qui est juste un extrait de Effective C++ de Scott Meyers). – GManNickG