6
votes

Comment puis-je vérifier l'échec du constructeur () sans utiliser d'exceptions?

Toutes les classes que je travaille ont créé () / détruire () (ou initialiser () / finalisées ()).

La valeur de retour de la méthode Create () est bool forte> comme ci-dessous. p> xxx pré>

afin que je puisse vérifier si l'initialisation de l'instance est réussie ou non de la valeur de retour. p>

sans créer () / détruire () Je peux faire le même travail dans le constructeur () et le destructeur () mais je ne peux pas résoudre en dessous de problème. P> Quelqu'un peut-il m'aider? Merci d'avance. P>

Je ne peux pas utiliser des exceptions parce que ma société ne l'aime pas. Em> p>

class Foo
{
private:
    AnotherClass a;
public:
    Foo()
    {
        if(a.Initialize() == false)
        {
            //???
            //Can I notify the failure to the user of this class without using exception?
        }
    }
    ...
};

Foo obj;


4 commentaires

Votre entreprise compte-t-elle que les exceptions sont présentes chaque fois qu'ils appellent neuf ou à tout moment ils utilisent la bibliothèque standard?


@Gman Nous avons tendance à remplacer l'opérateur nouveau. Et je ne sais pas sur les problèmes de la bibliothèque pourriez-vous me dire un peu plus?


Utilisez le mot-clé NOTHROWO dans ce cas pour éviter d'exception comme. int * p = nouvelle (NOTHROWOW) INT [100]; // sur l'échec retourne null pointeur mais comment allez-vous éviter la mauvaise exception Bad_cast, peut-être que vous devez éteindre une exception?


Un magasin que j'ai travaillé pour avoir eu une règle que les constructeurs ne peuvent pas échouer. Les constructeurs avaient donc très peu de code et les utilisateurs devaient appeler une méthode d'initialisation pouvant échouer. Ma compréhension était d'éliminer l'utilisation d'exceptions. Le code de la bibliothèque pour nouveau a été modifié pour ne pas lancer d'exceptions.


10 Réponses :


2
votes

Pourquoi les exceptions ne doivent pas être utilisées? La meilleure façon de retourner l'erreur du constructeur est de lancer l'exception. L'objet qui est construit à tort ne doit pas utiliser et lancer une exception garantit que.

Vous pouvez faire référence à cette FAQ: Comment Puis-je gérer un constructeur qui échoue?


1 commentaires

Comme Sevity a écrit: la politique de l'entreprise DIS-Permet des exceptions.



0
votes

Deux suggestions:

  • L'ancienne mode SETJMP / LONDJMP ()
  • une variable mondiale errno sim

0 commentaires

3
votes

Il n'y a pas de bon moyen; C'est l'une des principales raisons pour lesquelles ils ont été ajoutés à la langue en premier lieu. Sans exceptions non plus:

  1. effectuer une sorte d'affirmation () dans le constructeur pour arrêter l'exécution; impossible à ignorer, mais impossible à récupérer de.
  2. Faites votre construction réelle dans une fonction init.
  3. ... ou gardez-le dans le constructeur, mais définissez un drapeau "mauvais".

    Personnellement, je pense que 2 est strictement meilleur que 3, car il n'augmente pas la taille de la classe et le rend plus visible lorsque la fonction "Vérification" n'est pas appelée. Il y a des raisons d'entendre citée, comme si vous pouviez accéder aux fonctions virtuelles, mais j'ai toujours considéré cela pour être assez faible.


1 commentaires

Mais n'est-ce pas le point (2) et (3) essentiellement la même chose? Vous avez tous deux besoin d'un drapeau "mauvais" afin que les appels de méthodes ultérieurs puissent vérifier. Je discuterais au point (2) que vous minimisez les chances de l'utilisateur oubliant d'appeler la fonction «init ()».



10
votes

Si vous ne voulez pas utiliser des exceptions, il existe deux façons de laisser l'appelant savoir si le constructeur a réussi ou non:

  1. Le constructeur prend une référence / pointeur sur un paramètre qui communiquera le statut d'erreur à l'appelant.
  2. La classe implémente une méthode qui retournera l'état d'erreur du constructeur. L'appelant sera responsable de la vérification de cette méthode.

    Si vous accédez à l'une de ces techniques, assurez-vous que votre destructeur peut gérer une instance dans laquelle le constructeur a échoué.


0 commentaires

2
votes

Ceci est laid et je ne le recommande pas vraiment, mais em> si vous n'êtes pas autorisé à lancer dans le constructeur, vous pouvez avoir un constructeur muet et une fonction init:

class Foo
{
private:
    AnotherClass a;
public:
    Foo(){};
    bool initialize()
    {
        return a.Initialize();
    }
    ...
};

Foo obj;


2 commentaires

C'est la même chose que j'ai décrit comme créature () / détruire ().


Cela peut être la seule méthode fonctionnelle. Le problème est que les constructeurs peuvent être exécutés implicitement. Quand ils sont exécutés implicitement, vous ne pouvez pas vérifier le statut.



0
votes
class Foo
{
private:
    AnotherClass a;
    bool m_bInitFail; //store the status of initialization failure

public:
    Foo(bool bInitFail = false) : m_bInitFail(bInitFail)
    {
        m_bInitFail  = a.Initialize();           
    }

    bool GetInitStatus () { return m_bInitFail ; }
};

int main()
{
  Foo fobj;
  bool bStatus = fobj.GetInitStatus();
  return 0;         
}

0 commentaires

5
votes

C ++ sans exceptions est essentiellement une langue complètement différente de C ++, dans laquelle bon nombre des idiomes qui donnent C ++ Son puissance expressive unique sont rendus impuissants. Au fur et à mesure que vous le soulignez, les constructeurs sont dépouillés de leur utilité et que toute initialisation non séventielle doit être déplacée dans un pseudoconstructeur de deuxième étage pouvant renvoyer une indication d'erreur. (Certaines personnes préconisent également un pseudododododestructeur assorti d'un sens erroné de symétrie, mais qui est complètement inutile). Alternativement, le constructeur pourrait définir un drapeau "construit" sur le succès et chaque classe pourrait avoir une méthode "construite" qui vérifie ceci et tous ses enfants.

Si votre entreprise charge que vous désactivez des exceptions, vous aurez également besoin d'une convention à l'échelle de la société (ou au moins à l'échelle du projet) pour la remplacer. Vous devrez définir un type pour toutes les fonctions (non triviales) à revenir et utiliser de manière cohérente partout - sinon, vous obtiendrez un hodge-podge de booléens et incompatibles qui sont passés et convertis manuellement à tous les niveaux. < / p>

Dans ce cas, foo aura également besoin d'une méthode initialiser , qui appelle .Initialize et sort si cela échoue.


0 commentaires

2
votes

J'ai essayé toutes les alternatives aux exceptions que je pourrais trouver (variable d'erreur membre, même SetJMP / Longjmp), et ils ont tous sucé de leur manière particulière. Un motif très rare que je suis venu à l'amour consiste à transmettre une référence à un objet d'erreur et à vérifier si une erreur est en attente comme une toute première opération dans n'importe quelle fonction:

Derived o = guard_new(e, new(e) Derived(e));


1 commentaires

Au fait, je ne prends pas de crédit pour cette technique. Je pense que IBM l'a inventé, parce que le seul endroit que j'ai jamais vu est dans leur bibliothèque ICU



3
votes

Il est prudent d'éviter que le code provoque des défaillances au sein du constructeur ou du description. Avoir un membre supplémentaire dire, bool initialiser () , bool uninitialize () pour avoir ce genre de codes.


0 commentaires

3
votes

Je suis également tombé sur ce problème. Je pense que une solution élégante consiste à rendre le véritable constructeur privé, puis à utiliser une usine pour renvoyer une instance et l'erreur.

Je ne suis pas un fan de récupération d'une erreur via l'argument de sortie, alors je mettais ainsi le succès et Instance possible dans une structure: xxx

Il s'agit d'un modèle populaire qui est proposé comme extension de la norme. Les goodies en sont que votre code peut toujours utiliser fortement Raii.

Je recommande de regarder Andrei Alexandrescu's Parlez sur la manipulation des erreurs systématiques en C ++ .


0 commentaires