C++
Les attributs
Recherche…
Syntaxe
[[détails]]: attribut simple sans argument
[[détails (arguments)]]: attribut avec arguments
__attribute (détails): spécifique GCC / Clang / IBM non standard
__declspec (détails): Spécifique à MSVC non standard
[[non-retour]]
C ++ 11 a introduit l'attribut [[noreturn]]
. Il peut être utilisé pour une fonction pour indiquer que la fonction ne retourne pas à l'appelant soit en exécutant une instruction return , soit en atteignant la fin si c'est un corps (il est important de noter que cela ne s'applique pas aux fonctions void
, car retourne à l'appelant, ils ne renvoient juste aucune valeur). Une telle fonction peut se terminer en appelant std::terminate
ou std::exit
ou en lançant une exception. Il convient également de noter qu'une telle fonction peut être longjmp
exécutant longjmp
.
Par exemple, la fonction ci-dessous jettera toujours une exception ou appellera std::terminate
, ce qui en fait un bon candidat pour [[noreturn]]
:
[[noreturn]] void ownAssertFailureHandler(std::string message) {
std::cerr << message << std::endl;
if (THROW_EXCEPTION_ON_ASSERT)
throw AssertException(std::move(message));
std::terminate();
}
Ce type de fonctionnalité permet au compilateur de mettre fin à une fonction sans instruction de retour s'il sait que le code ne sera jamais exécuté. Ici, comme l'appel à ownAssertFailureHandler
(défini ci-dessus) dans le code ci-dessous ne reviendra jamais, le compilateur n'a pas besoin d'ajouter de code en dessous de cet appel:
std::vector<int> createSequence(int end) {
if (end > 0) {
std::vector<int> sequence;
sequence.reserve(end+1);
for (int i = 0; i <= end; ++i)
sequence.push_back(i);
return sequence;
}
ownAssertFailureHandler("Negative number passed to createSequence()"s);
// return std::vector<int>{}; //< Not needed because of [[noreturn]]
}
Il s'agit d'un comportement indéfini si la fonction est effectivement renvoyée. Par conséquent, les éléments suivants ne sont pas autorisés:
[[noreturn]] void assertPositive(int number) {
if (number >= 0)
return;
else
ownAssertFailureHandler("Positive number expected"s); //< [[noreturn]]
}
Notez que le [[noreturn]]
est principalement utilisé dans les fonctions vides. Cependant, ce n'est pas une exigence, permettant aux fonctions d'être utilisées dans la programmation générique:
template<class InconsistencyHandler>
double fortyTwoDivideBy(int i) {
if (i == 0)
i = InconsistencyHandler::correct(i);
return 42. / i;
}
struct InconsistencyThrower {
static [[noreturn]] int correct(int i) { ownAssertFailureHandler("Unknown inconsistency"s); }
}
struct InconsistencyChangeToOne {
static int correct(int i) { return 1; }
}
double fortyTwo = fortyTwoDivideBy<InconsistencyChangeToOne>(0);
double unreachable = fortyTwoDivideBy<InconsistencyThrower>(0);
Les fonctions de bibliothèque standard suivantes ont cet attribut:
- std :: abort
- std :: exit
- std :: quick_exit
- std :: unknown
- std :: terminate
- std :: rethrow_exception
- std :: throw_with_nested
- std :: nested_exception :: rethrow_nested
[[tomber dans]]
Chaque fois qu'un case
se termine dans un switch
, le code du cas suivant sera exécuté. Ce dernier peut être empêché en utilisant l'instruction ´break`. Comme ce soi-disant comportement trompeur peut introduire des bogues lorsqu'il n'est pas prévu, plusieurs compilateurs et analyseurs statiques émettent un avertissement à ce sujet.
A partir de C ++ 17, un attribut standard a été introduit pour indiquer que l'avertissement n'est pas nécessaire lorsque le code est censé tomber. Les compilateurs peuvent donner des avertissements en toute sécurité lorsqu'un dossier est terminé sans break
ou [[fallthrough]]
et possède au moins une instruction.
switch(input) {
case 2011:
case 2014:
case 2017:
std::cout << "Using modern C++" << std::endl;
[[fallthrough]]; // > No warning
case 1998:
case 2003:
standard = input;
}
Voir la proposition pour des exemples plus détaillés sur la manière dont [[fallthrough]]
peut être utilisé.
[[déconseillé]] et [[déconseillé ("raison")]]
C ++ 14 a introduit un moyen standard de déconseiller les fonctions via des attributs. [[deprecated]]
peut être utilisé pour indiquer qu'une fonction est obsolète. [[deprecated("reason")]]
permet d'ajouter une raison spécifique pouvant être affichée par le compilateur.
void function(std::unique_ptr<A> &&a);
// Provides specific message which helps other programmers fixing there code
[[deprecated("Use the variant with unique_ptr instead, this function will be removed in the next release")]]
void function(std::auto_ptr<A> a);
// No message, will result in generic warning if called.
[[deprecated]]
void function(A *a);
Cet attribut peut être appliqué à:
- la déclaration d'une classe
- un nom de typedef
- une variable
- un membre de données non statique
- une fonction
- une énumération
- une spécialisation de template
(réf. c ++ 14 brouillon standard : 7.6.5 Attribut obsolète)
[[nodiscard]]
L'attribut [[nodiscard]]
peut être utilisé pour indiquer que la valeur de retour d'une fonction ne doit pas être ignorée lors d'un appel de fonction. Si la valeur de retour est ignorée, le compilateur doit en avertir. L'attribut peut être ajouté à:
- Une définition de fonction
- Un type
L'ajout de l'attribut à un type a le même comportement que l'ajout de l'attribut à chaque fonction unique qui renvoie ce type.
template<typename Function>
[[nodiscard]] Finally<std::decay_t<Function>> onExit(Function &&f);
void f(int &i) {
assert(i == 0); // Just to make comments clear!
++i; // i == 1
auto exit1 = onExit([&i]{ --i; }); // Reduce by 1 on exiting f()
++i; // i == 2
onExit([&i]{ --i; }); // BUG: Reducing by 1 directly
// Compiler warning expected
std::cout << i << std::end; // Expected: 2, Real: 1
}
Voir la proposition pour des exemples plus détaillés sur la façon dont [[nodiscard]]
peut être utilisé.
Remarque: Les détails d'implémentation de Finally
/ onExit
sont omis dans l'exemple, voir Finally / ScopeExit .
[[peut-être_unused]]
L'attribut [[maybe_unused]]
est créé pour indiquer dans le code qu'une certaine logique pourrait ne pas être utilisée. Ceci est souvent lié aux conditions du préprocesseur où cela pourrait être utilisé ou ne pas être utilisé. Comme les compilateurs peuvent donner des avertissements sur les variables inutilisées, cela permet de les supprimer en indiquant leur intention.
Un exemple typique de variables nécessaires dans les versions de débogage, même si elles sont inutiles en production, sont les valeurs de retour indiquant le succès. Dans les versions de débogage, la condition doit être affirmée, bien que, en production, ces assertions aient été supprimées.
[[maybe_unused]] auto mapInsertResult = configuration.emplace("LicenseInfo", stringifiedLicenseInfo);
assert(mapInsertResult.second); // We only get called during startup, so we can't be in the map
Un exemple plus complexe est celui des différentes fonctions d'aide qui se trouvent dans un espace de noms sans nom. Si ces fonctions ne sont pas utilisées lors de la compilation, un compilateur peut les avertir. Idéalement, vous voudriez les garder avec les mêmes balises de préprocesseur que l'appelant, bien que cela puisse devenir complexe, l'attribut [[maybe_unused]]
est une alternative plus [[maybe_unused]]
maintenir.
namespace {
[[maybe_unused]] std::string createWindowsConfigFilePath(const std::string &relativePath);
// TODO: Reuse this on BSD, MAC ...
[[maybe_unused]] std::string createLinuxConfigFilePath(const std::string &relativePath);
}
std::string createConfigFilePath(const std::string &relativePath) {
#if OS == "WINDOWS"
return createWindowsConfigFilePath(relativePath);
#elif OS == "LINUX"
return createLinuxConfigFilePath(relativePath);
#else
#error "OS is not yet supported"
#endif
}
Voir la proposition pour des exemples plus détaillés sur la façon dont [[maybe_unused]]
peut être utilisé.