6
votes

Comment retourner NULL d'une méthode dans une classe de modèle

J'ai une méthode qui ressemble à ceci:

template <typename T>
T Test<T>::FindItem(T item)
{
    if(found)
        //return original value, no problem here
    else
        //I want to return NULL here, like:
        return NULL; 
}


5 commentaires

C'est une erreur de temps compilée. Pas un temps d'exécution.


Temps d'exécution pour std :: String, STD :: String (Cons-Char *) sera appelé


@Naveed: J'utilise le compilateur VC de Visual Studio 2005 et ce n'est pas une erreur de compilation de la compilation. Ne peut pas dire à propos de GCC.


Oups..solire mon erreur. Oui, il se bloque dans VS2008 également.


Initialisation d'un std :: String avec NULL n'est pas une erreur de compilation, mais invoquera un comportement non défini, échoué probablement au moment de l'exécution.


9 Réponses :


2
votes

La plupart des types sont construcables par défaut que vous avez une classe de modèle de traits qui peut être spécialisée (avec le renvoi par défaut d'un objet initialisé par défaut).

template <class T>
struct Make {
    static T Default()
    {
         return T();
    }
};


class not_default_constructable {
public:
    explicit not_default_constructable(int i) {}
};

// specialize for not_default_constructable     
template <>
struct Make <not_default_constructable> {
    static not_default_constructable Default()
    {
         return not_default_constructable(42);
    }
};


0 commentaires

9
votes

ici , Stroustrup donne quelques arguments pour éviter < Code> null en C ++:

  • La définition est juste 0 , il n'y a donc pas de gain réel [et plus à taper]
  • C'est une macro et les macros sont mieux évités dans C ++

    La suggestion, à nouveau de cette page est la suivante:

    • Utilisez une plaine 0 ou (pour c ++ 0xwateverver) nullptr .

      Deuxièmement, si vous souhaitez renvoyer un pointeur non valide comme signal de défaillance, vous devez déclarer la fonction comme renversant un pointeur à un type, pas le type lui-même.

      Troisièmement, la plupart des fonctions de bibliothèque standard () devront renvoyer des itérateurs, plutôt que des éléments directement. Cela vous donne la possibilité de mettre en œuvre le cas "rien trouvé" différemment.


7 commentaires

Pourquoi ne pas utiliser null? Pour moi, il est plus clair que vous traitez avec des pointeurs Iso. entiers de cette façon.


L'utilisation ou non de NULL est une question de style de codage juste à côté de la position des supports curcly ou du nombre d'espaces à utiliser lors de l'indentation. J'ai utilisé les deux, je ne préfère pas l'un sur l'autre tant qu'il est utilisé de manière cohérente. Il y a des arguments à la fois, je ne pense pas que j'ai entendu parler de convaincant.


@ Kristof: Stroustrup fait un argument assez marginal contre - recherche.att.com/ ~ bs / bs_faq2.html # null


@ Kristof: J'ai ajouté que très lien avec la réponse elle-même, avant de voir que c'était déjà ici dans votre commentaire. Je vais le laisser, mais merci!


Le fait que C ++ manque de mot-clé null est une défaillance de la conception de la langue, malgré tout argument STROSTRUP. Les pointeurs sont différents des entiers, de la période et doivent donc être syntaxiquement différentes.


Eh bien, la non-existence du mot-clé NULL (à rectifier en C ++ 0x) est un symptôme du fait que les pointeurs et les entiers peuvent être convertis implicitement. Je pense que c'est un pire échouage (et les auteurs de GCC sont d'accord, car il y a un avertissement pour cela), mais il est hérité de C et de supprimer, il s'agirait probablement d'une rupture de compatibilité pour le comité C ++.


Vous dites "N'utilisez pas NULL", reliant la déclaration de STROSTRUP où il dit "en C ++, la définition de NULL est 0, donc il n'y a qu'une différence esthétique.". Semble étrange - je suis sûr que STROSTRUP ne dirait pas "N'utilisez pas NULL".



15
votes

Si vous souhaitez revenir en valeur et que vous ne voulez pas gâcher avec des pointeurs de retour et de nouveau / Supprimer, vous pouvez simplement faire comme suit:

Test<int> var;
boost::optional<int> V = var.FindItem(5)

if (V)
{
    // found
    int val = *V;
}
else
{
    // not found
}


2 commentaires

Je n'utilise pas boost alors ne peut pas utiliser boost :: aucun


Si vous souhaitez renvoyer une valeur singulière pour un type qui n'en avez pas, vous devrez utiliser facultatif ou quelque chose d'équivalent. Si vous n'avez pas accès à Boost, vous pouvez toujours définir la vôtre (un autre nom commun utilisé pour cela est faillible).



2
votes

Vous devez retourner t * non t


0 commentaires

2
votes

Peut-être que je suis trop simpliste, mais je préfère simplement retourner un bool : xxx


2 commentaires

-1 Sauf que cela ne fonctionne pas, car la fonction prend élément par copie.


Si vous retournez une copie de l'élément d'origine lors de sa constatation (comme indique le commentaire dans le code de l'Asker), vous pourriez aussi bien retourner un BOOL. L'appelant a déjà l'article.



7
votes

Vous avez une fonction qui pourrait renvoyer un objet valide, mais également une indication qu'aucun objet valide n'existe. Combiné à une situation dans laquelle toutes les valeurs d'objet possibles sont valides, il s'agit d'un problème de conception avec votre fonction de recherche. (Même si vous avez modifié la fonction de manière à renvoyer une chaîne vide si elle n'en trouve pas une, comment cela se distinguerait-il de manière réussie de trouver une chaîne vide?)

Au fil du temps, plusieurs moyens de sortir de ce dilemme ont été trouvés. Vous pouvez donc retourner un pointeur / itérateur au lieu de retourner la valeur réelle. Ensuite, un NULL Le pointeur / End Itérateur indiquerait "non trouvé". Ou vous pouvez prendre une valeur par référence non-Const, attribuez-lui le résultat et indiquer le succès / l'échec par un booléen retourné. Ou prenez l'une des autres solutions postées ici. Mais tous nécessiteront que vous modifiez l'interface de la fonction - car, comme il s'agit d'une erreur de conception.

Quoi qu'il en soit, avant de sauter et faites-le, vous devez vous demander pourquoi vous écrivez votre propre conteneur / algorithme au lieu d'en utiliser un de STD LIB.


0 commentaires

1
votes

retour t () . Si t est de type Détype * , il sera initialisé à un pointeur NULL. Si t est de type Automype , il retournera un objet créé avec le constructeur par défaut, qui devrait suffire ( std :: string sera vide , des types intégrés tels que int s seront 0, etc.).


1 commentaires

Cela ne fonctionne pas si 0 est une valeur de retour valide. ATOI () a le même problème.



1
votes

À mon avis, vous essayez de vous compliquer un peu en essayant de retourner une valeur nulle ...

faire quelque chose de similaire à celui-ci: xxx

Lancer une classe vide ne coûte rien ...


0 commentaires

1
votes

Vous pouvez lancer une exception lorsqu'il n'est pas trouvé.

Depuis que vous n'avez aucune connaissance du type étant recherché et renvoyé, vous ne pouvez désigner aucune valeur particulière de ce type comme code d'erreur. En substance, vous essayez de serrer le domaine complet d'un type plus une valeur d'erreur dans le domaine du type.

Les suggestions d'utilisation d'itérateurs ou d'autres emballages aident à résoudre le problème en étendant le domaine du type de retour pour englober les valeurs d'erreur, mais si vous souhaitez vous tenir aux types réels que vous avez affaire, des exceptions sont votre meilleur choix. C'est ce qu'ils sont pour.


0 commentaires