Traitement de l’avertissement «initialisé mais non référencé» C ++ pour la destruction des aides de la portée?

StackOverflow https://stackoverflow.com/questions/219770

Question

Dans Visual Studio, j'utilise souvent des objets uniquement à des fins RAII. Par exemple:

ScopeGuard close_guard = MakeGuard( &close_file, file );

close_guard a pour seul objectif de s’assurer que le fichier sera fermé à la sortie de la fonction, il n’est utilisé nulle part ailleurs. Cependant, Visual Studio me prévient qu'une " variable locale est initialisée mais non référencée ". Je souhaite désactiver cet avertissement pour ce cas particulier.

Comment gérez-vous ce genre de situation? Visual Studio pense que cet objet est inutile, mais c'est faux car il a un destructeur non trivial.

Je ne voudrais pas utiliser une directive #pragma warning pour cela car cela désactiverait cet avertissement même pour des raisons légitimes.

Était-ce utile?

La solution

Méthode 1: utilisez la directive #pragma warning .

#pragma warning permet une modification sélective du comportement des messages d'avertissement du compilateur.

#pragma warning( push )
#pragma warning( disable : 4705 ) // replace 4705 with warning number

ScopeGuard close_guard = MakeGuard( &close_file, file );

#pragma warning( pop )

Ce code enregistre l'état d'avertissement actuel, puis le désactive pour un code d'avertissement spécifique, puis restaure le dernier état d'avertissement enregistré.

Méthode 2: utilisez une solution de contournement semblable à celle-ci. Visual Studio sera heureux et vous aussi. Cette solution de contournement est utilisée dans de nombreux exemples Microsoft et également dans d'autres projets.

ScopeGuard close_guard = MakeGuard( &close_file, file );
close_guard;

Vous pouvez également créer un #define pour contourner l'avertissement.

#define UNUSED_VAR(VAR) VAR
...
ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED_VAR(close_guard);

Certains utilisateurs ont déclaré que le code présenté ne fonctionnerait pas car ScopeGuard était un typedef. Cette hypothèse est fausse.

http://www.ddj.com/cpp/184403758

  

Selon la norme C ++, un   référence initialisée avec un temporaire   la valeur fait vivre cette valeur temporaire   pour la durée de vie de la référence   lui-même.

Autres conseils

Si votre objet dispose d'un destructeur non trivial, Visual Studio ne doit pas vous avertir. Le code suivant ne génère aucun avertissement dans VS2005 si les avertissements sont remontés au maximum (/ W4):


class Test
{
public:
    ~Test(void) { printf("destructor\n"); }
};

Test foo(void) { return Test(); }

int main(void)
{
    Test t = foo();
    printf("moo\n");

    return 0;
}

La mise en commentaire du destructeur donne un avertissement; le code tel quel n'est pas.

Nous utilisons:

static_cast<void>(close_guard);

pour les variables dont le compilateur se plaint.

Dans certains fichiers d’en-tête de VC ++, MS définit une macro:

#define UNUSED(x) x

utilisé comme:

ScopeGuard close_guard = MakeGuard( &close_file, file );
UNUSED(close_guard);

Ce qui fait taire l'avertissement et le documente.

J'utiliserais la macro jusqu'au bout dans ce cas:

#define SCOPE_GUARD(guard, fn, param) \
    ScopeGuard guard = MakeGuard(fn, param); \
    static_cast<void>(guard)

maintenant votre code est beau et court:

SCOPE_GUARD(g1, &file_close, file1);
SCOPE_GUARD(g2, &file_close, file2);

L'un des avantages de cette approche est que vous pouvez ajouter ultérieurement __ LINE __ , __ func __ , etc., afin de consigner les actions de protection ultérieurement, si nécessaire.

Eh bien, dans ce cas, ScopeGuard est en fait une modification de type vers un type de référence. Cela ne fonctionnerait malheureusement pas.

Cela ne signifie-t-il pas que tout ScopeGuard ne fonctionne pas, car dans ce cas, le destructeur ne s'appellera pas ???

Vous pouvez limiter l'avertissement #pragma à cette ligne de code uniquement à l'aide de

.
#pragma warning(push)
#pragma warning(disable:XXXX)
your code here;
#pragma warning(pop)

ou

#pragma warning(disable:XXXX)
your code here;
#pragma warning(default:XXXX)

Vous pouvez également utiliser UNREFERENCED_PARAMETER (close_guard); après la ligne de code ci-dessus.

En pratique, j'imagine que j'allais avec le #pragma disable ... ou "UNUSED". Cependant, en règle générale, le code doit être gardé à l’abri des avertissements, même au prix de quelques encombrements supplémentaires. Il doit compiler dans plusieurs compilateurs différents sur différentes plates-formes et systèmes d'exploitation sans avertissements. Si ce n'est pas le cas, le code doit être corrigé pour qu'il le soit. Conserver du code qui génère des avertissements au niveau gcc -Wall n’est pas une bonne idée.

Les avertissements du compilateur sont vos amis et doivent être pris en compte, en principe ou en principe. Même lorsque cela signifie que les choses doivent être mises en œuvre de manière un peu plus volumineuse et verbeuse. Se rentabilise à long terme, car le code est porté, maintenu et vit éternellement ...

Essayez d'ajouter 'volatile' à la déclaration ScopeGuard.

J'utilise le message de smink ci-dessus et je n'ai qu'à ajouter que je colle un commentaire à côté du #define disant // utilisé pour supprimer l'avertissement [numéro d'avertissement] dans Visual Studio

Vous pouvez créer explicitement l'objet ScopeGuardImpl1, à condition qu'il n'y ait pas tellement de paramètres dans les cas que vous utilisez que le résultat est illisible. De cette façon, vous évitiez la référence initialisée avec temporaire que l'alerte VS ne semble apparemment pas comprendre. Le coût est d’avoir à épeler les choses longuement, plutôt que d’obtenir le modèle magique de MakeGuard.

Le problème fondamental ici semble être que le compilateur ne comprend pas très bien à quoi vous visez ... ce qui semble être d'utiliser la sémantique exploratoire en C ++ pour obtenir du code appelé lorsqu'une variable est désallouée, même lorsqu'elle est désallouée. ne pas être utilisé. Droite? Ce mécanisme lui-même me semble être à la limite ... un compilateur devrait avoir le droit de supprimer les variables inutilisées, mais la sémantique de la construction C ++ gâche vraiment tout cela. Pas d’autre moyen de faire cela sans avoir un tour de passe-passe?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top