2017-09-17 2 views
3

Voici deux extraits très similaires:Devrais-je utiliser static_cast dans les affectations et les déclarations de retour et pourquoi?

vector<int> a; 
int n = static_cast<int>(a.size()); 
// --------- 
int f(const vector<int>& a) { 
    return static_cast<int>(a.size()); 
} 

Ici, je convertir explicitement une valeur de type size_t à taper int. Si j'omets static_cast alors la même distribution s'applique implicitement.

De quel type cette distribution implicite serait-elle? Est-il prudent d'omettre static_cast dans les affectations explicites et les déclarations de retour?

+0

Je préférerais changer le type de n et le type de retour de f ainsi coulé ne sera pas nécessaire. Mais si vous devez utiliser un type incompatible, la distribution explicite est prefferebale pour montrer qu'il se passe quelque chose de louche sur cette ligne. Et le compilateur approprié avec les paramètres warnig de haut niveau ne permettra pas à ce code de compiler sans lancer –

Répondre

1

Cette fonte est pas sûr, actualy la valeur de n peut être mise en œuvre définie (C++ standard [conv .integral]):

Si le type de destination est signé, la valeur reste inchangée s'il peut être représenté dans le type de destination sinon, la valeur est définie par l'implémentation.

Si vous activez tous les avertissements et n'utilisez pas static_cast, votre compilateur peut vous informer d'une conversion plus étroite. Si vous utilisez le static_cast, vous informez le lecteur de votre code que vous savez avec certitude que a.size() <= std::numeric_limits<int>::max() ou que vous savez ce que votre implémentation va faire si une telle condition ne tient pas.

(avis qu'il pourrait être possible que la comparaison précédente invoque également la conversion définie de mise en œuvre si std :: size_t est plus petit que int, le standard C++ allowes il)

+0

Cette réponse explique mieux ce qui se passe ici plutôt que de suggérer d'autres bonnes pratiques. J'apprécie, mais par le biais de cette question, j'étais particulièrement intéressé par les détails de ce comportement. Merci. –

+0

@IvanSmirnov :), je lisais juste CppCoreGuidelines et ils proposent d'implémenter un narrow_cast pour cette distribution spécifique. En outre, il existe une fonction 'narrow', qui vérifie en mode debug que la conversion ne change pas la valeur, https: // github.com/Microsoft/GSL/blob/maître/include/gsl/gsl_util – Oliv

3

Ce serait une conversion intégrale. Et un rétrécissement à cela.

Pour l'initialisation variable si vous voulez un type spécifique, une bonne approche est de faire ce que Herb Sutter suggère dans son « presque toujours Auto » GotW article:

auto n = int{a.size()}; 

Utiliser l'initialisation de la liste chaque fois que possible. Cela évitera de réduire les conversions et votre compilateur utilisera une distribution explicite si nécessaire (comme dans le cas ci-dessus).

2

La nécessité de la coulée est nécessairement déterminée par la conversion nécessaire. Donc la vraie question ici devrait être "pourquoi devrais-je retourner/stocker un int au lieu de vector<int>::size_type?" Si votre logique de programme ne nécessite pas vraiment une telle conversion, ne l'exécutez pas du tout. Si votre logique de programme nécessite une telle conversion (par exemple, vous devez passer cette valeur dans un appel à une fonction tierce qui accepte int), vous devez utiliser static_cast. Omettre static_cast dans ce cas serait un signe de conversion de rétrécissement involontaire et déclenche des avertissements du compilateur correspondants, tels que warning C4267: 'initializing': conversion from 'size_t' to 'int', possible loss of data ou warning: conversion to 'int' from 'std::vector<int>::size_type {aka long unsigned int}' may alter its value [-Wconversion]