2011-12-03 1 views
1

Selon Herb Sutter le code ci-dessous ne compilerait pas. Voir ce site http://www.gotw.ca/gotw/066.htm d'où j'ai extrait le texte suivant, en ce qui concerne function-try-blocks:Selon un auteur averti de la communauté C++, le code ci-dessous ne doit pas être compilé. Il a tort?

Vers Certains Morals

Soit dit en passant, cela signifie aussi que la seule (répéter seulement) utilisation possible pour un constructeur function-try-block est de traduire une exception levée à partir d'un sous-objet de base ou de membre. C'est Morale # 1. Ensuite, Moral # 2 dit que destructeur fonction-try-blocs sont entièrement usele--

"--Mais attendez!" J'entends quelqu'un interrompre au milieu de la pièce. "Je ne suis pas d'accord avec Moral 1. Je peux penser à une autre utilisation possible pour constructor function-try-blocks, à savoir pour libérer les ressources allouées en la liste des initialiseurs ou dans le corps du constructeur!"

Désolé, non. Après tout, n'oubliez pas qu'une fois que vous entrez dans votre constructeur, les variables locales dans le corps du constructeur sont également hors de portée, et vous avez la garantie qu'aucun sous-objet de base ou objet membre n'existe plus, point. Vous ne pouvez même pas faire référence à leurs noms. Soit les parties de votre objet n'ont jamais été construites, soit celles qui ont été construites ont déjà été détruites. Donc, vous ne pouvez pas nettoyer tout ce qui repose sur en référence à une base ou un membre de la classe (et de toute façon, c'est ce que les destructeurs de base et membres sont pour, non?).

En supposant cette citation, le code suivant ne devrait pas compiler, comme l'objet cat a déjà été détruite au moment où le processus se heurte à la clause catch. Mais c'est le cas, au moins avec VSC2008.

class Cat 
{ 
    public: 
    Cat() { cout << "Cat()" << endl; } 
    ~Cat() { cout << "~Cat()" << endl; } 
}; 

class Dog 
{ 
    public: 
    Dog() { cout << "Dog()" << endl; throw 1; } 
    ~Dog() { cout << "~Dog()" << endl; } 
}; 


class UseResources 
{ 
    class Cat *cat; 
    class Dog dog; 

    public: 
    UseResources(); 
    ~UseResources() { delete cat; cat = NULL; cout << "~UseResources()" << endl; } 
}; 

UseResources::UseResources() try : cat(new Cat), dog() { cout << "UseResources()" << endl; } catch(...) 
{ 
    delete cat; 
    throw; 
} 

Répondre

2

Je ne pense pas que Herb Sutter dise réellement qu'il ne compilera pas. Il est en train d'expliquer les conséquences de ce que la norme doit dire au sujet de la situation (15.3.10):

Se référant à un membre non-statique ou classe de base d'un objet dans le gestionnaire pour une fonction essayer -bloc d'un constructeur ou d'un destructeur pour cet objet donne comportement indéfini.

+0

+1 pour citer la partie pertinente de la norme. –

0

Compilateurs sont différents, et il y a aussi des commutateurs qui déterminent à quel point le compilateur sera stricte avec le code qu'il compile. ce code provoquera certainement des erreurs (erreurs de segment, etc.). essayez d'activer tous les commutateurs du compilateur pour le forcer à le trouver.

+0

-Wall est votre ami. Je crois que l'équivalent de MSVC++ est/W4. – moshbear

+0

@moshbear Avec/W4 j'ai 'C4702: code inaccessible' se référant au constructeur' Dog'. Je n'ai pas compris. – Belloc

+0

@moshbear L'avertissement fait référence au fait que la fin du constructeur 'Dog' est inaccessible, ce qui est vrai, en raison de l'instruction' throw 1; ' – Belloc

1

En supposant cette citation, le code suivant ne doit pas compiler ...

Eh bien, il n'a pas dit qu'ils ne seraient jamais compiler. Si quelque chose, j'ai interprété la citation comme signifiant «faire ceci est indéfini». Un comportement indéfini peut avoir n'importe quel résultat - jusqu'à et y compris compiler avec succès, et faire des choses surprenantes plus tard.

+0

'Désolé, non. Après tout, n'oubliez pas qu'une fois que vous entrez dans le gestionnaire try-block de votre constructeur, toutes les variables locales dans le corps du constructeur sont déjà hors de portée, et vous êtes garanti qu'aucun sous-objet de base ou objet membre n'existe plus. Vous ne pouvez même pas vous référer à leurs noms. » – Belloc

+2

Oui, et où cela signifie-t-il qu'il ne sera pas compilé? –

Questions connexes