Zoeken…


Syntaxis

  • [[details]]: Eenvoudig kenmerk zonder argument

  • [[details (argumenten)]]: Kenmerk met argumenten

  • __attribuut (details): niet-standaard GCC / Clang / IBM-specifiek

  • __declspec (details): niet-standaard MSVC-specifiek

[[geen terugkeer]]

C ++ 11

C ++ 11 introduceerde het [[noreturn]] attribuut. Het kan worden gebruikt voor een functie om aan te geven dat de functie niet terugkeert naar de beller door een terugkeerinstructie uit te voeren of door het einde te bereiken als het hoofdgedeelte is (het is belangrijk op te merken dat dit niet van toepassing is op void functies, omdat ze keren terug naar de beller, deze retourneert gewoon geen waarde). Een dergelijke functie kan eindigen door std::terminate of std::exit aan te roepen, of door een uitzondering te maken. Het is ook vermeldenswaard dat een dergelijke functie kan terugkeren door longjmp .

De onderstaande functie zal bijvoorbeeld altijd een uitzondering [[noreturn]] of std::terminate aanroepen, dus het is een goede kandidaat voor [[noreturn]] :

[[noreturn]] void ownAssertFailureHandler(std::string message) {
    std::cerr << message << std::endl;
    if (THROW_EXCEPTION_ON_ASSERT)
        throw AssertException(std::move(message));
    std::terminate();
}

Met dit soort functionaliteit kan de compiler een functie beëindigen zonder een retourinstructie als hij weet dat de code nooit zal worden uitgevoerd. Omdat de aanroep naar ownAssertFailureHandler (hierboven gedefinieerd) in de onderstaande code nooit zal terugkeren, hoeft de compiler geen code toe te voegen onder die aanroep:

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]]
}

Het is ongedefinieerd gedrag als de functie daadwerkelijk terugkeert, dus het volgende is niet toegestaan:

[[noreturn]] void assertPositive(int number) {
    if (number >= 0)
        return;
    else
        ownAssertFailureHandler("Positive number expected"s); //< [[noreturn]]
}

Merk op dat de [[noreturn]] meestal wordt gebruikt in nietige functies. Dit is echter geen vereiste, zodat de functies kunnen worden gebruikt in generieke programmering:

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);

De volgende standaard bibliotheekfuncties hebben dit kenmerk:

  • std :: afbreken
  • std :: exit
  • std :: quick_exit
  • std :: onverwacht
  • std :: beëindigen
  • std :: rethrow_exception
  • std :: throw_with_nested
  • std :: nested_exception :: rethrow_nested

[[Fallthrough]]

C ++ 17

Wanneer een case wordt beëindigd in een switch , wordt de code van de volgende zaak uitgevoerd. Dit laatste kan worden voorkomen door de ´break`-instructie te gebruiken. Omdat dit zogenaamde doorbraakgedrag bugs kan introduceren als het niet de bedoeling is, geven verschillende compilers en statische analyzers hier een waarschuwing voor.

Vanaf C ++ 17 werd een standaardkenmerk geïntroduceerd om aan te geven dat de waarschuwing niet nodig is wanneer de code er doorheen moet vallen. Compilers kunnen veilig waarschuwingen geven wanneer een case zonder break of [[fallthrough]] wordt beëindigd en ten minste één verklaring heeft.

switch(input) {
    case 2011:
    case 2014:
    case 2017:
        std::cout << "Using modern C++" << std::endl;
        [[fallthrough]]; // > No warning
    case 1998:
    case 2003:
        standard = input;
}

Zie het voorstel voor meer gedetailleerde voorbeelden over hoe [[fallthrough]] kan worden gebruikt.

[[verouderd]] en [[verouderd ("reden")]]

C ++ 14

C ++ 14 introduceerde een standaardmanier om functies via attributen af te schrijven. [[deprecated]] kan worden gebruikt om aan te geven dat een functie is verouderd. [[deprecated("reason")]] maakt het mogelijk een specifieke reden toe te voegen die door de compiler kan worden getoond.

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);

Dit kenmerk kan worden toegepast op:

  • de verklaring van een klasse
  • een typefef-naam
  • een variabele
  • een niet-statisch gegevenslid
  • een functie
  • een opsomming
  • een sjabloon specialisatie

(ref. c ++ 14 standaardontwerp : 7.6.5 Verouderd kenmerk)

[[Nodiscard]]

C ++ 17

Het kenmerk [[nodiscard]] kan worden gebruikt om aan te geven dat de retourwaarde van een functie niet mag worden genegeerd wanneer u een functieaanroep doet. Als de retourwaarde wordt genegeerd, moet de compiler hierover een waarschuwing geven. Het kenmerk kan worden toegevoegd aan:

  • Een functiedefinitie
  • Een type

Het toevoegen van het kenmerk aan een type heeft hetzelfde gedrag als het toevoegen van het kenmerk aan elke functie die dit type retourneert.

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
}

Zie het voorstel voor meer gedetailleerde voorbeelden over hoe [[nodiscard]] kan worden gebruikt.

Let op: De implementatie details van de Finally / onExit zijn weggelaten in het voorbeeld, zie Eindelijk / ScopeExit .

[[Maybe_unused]]

Het kenmerk [[maybe_unused]] is gemaakt om in code aan te geven dat bepaalde logica mogelijk niet wordt gebruikt. Dit indien vaak gekoppeld aan preprocessor-omstandigheden waarin dit al dan niet kan worden gebruikt. Omdat compilers waarschuwingen kunnen geven over ongebruikte variabelen, is dit een manier om ze te onderdrukken door intentie aan te geven.

Een typisch voorbeeld van variabelen die nodig zijn bij debug-builds terwijl ze niet nodig zijn in de productie zijn retourwaarden die op succes wijzen. In de debug-builds moet de voorwaarde worden bevestigd, hoewel deze beweringen in productie zijn verwijderd.

[[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

Een meer complex voorbeeld zijn verschillende soorten helpfuncties die zich in een naamloze naamruimte bevinden. Als deze functies niet worden gebruikt tijdens het compileren, kan een compiler een waarschuwing geven. In het ideale geval wilt u ze beschermen met dezelfde preprocessor-tags als de beller, maar omdat dit complex kan worden, is het kenmerk [[maybe_unused]] een beter te onderhouden alternatief.

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
}

Zie het voorstel voor meer gedetailleerde voorbeelden over hoe [[maybe_unused]] kan worden gebruikt.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow