functie probeer catch syntax en main

Een weinig bekende, maar bijna nooit gebruikte C ++ -functie krijgt een verklaring:

void foo();

Een mogelijke, wettelijke definitie zou kunnen zijn:

void foo() try {
  throw 42;
}
catch(...) {
}

Hier is de hele functie implementatie geïmplementeerd binnen een try / catch -paar , dat lijkt op het toestaan ​​van dit .

Is dat legaal om te doen voor int main() ? bijv .:

int main() try {
  throw 42;
}
catch(...) {
}

The rules for main, n3290 § 3.6.1 mostly talk about what arguments it should take and what it returns - they don't seem to explicitly forbid it as they do with various other odd things (e.g. linkages) you might be tempted to try.

Is dit legaal en duidelijk omschreven?

15
Als het niet "door de implementatie gedefinieerd gedrag" is, maakt dit dan niet automatisch "ongedefinieerd gedrag"?
toegevoegd de auteur Mr. Llama, de bron
Leuke vraag :) Het is misschien een omissie geweest want ik ben verrast, voor het geval dat dit is toegestaan, dat er geen nauwkeurigheid is op de geretourneerde waarde in de clausule catch . Het kan worden gedekt door het feit dat de geretourneerde waarde "standaard" is in 0 ... dunno
toegevoegd de auteur Matthieu M., de bron
Wat is de exacte vraag? Of een functie een functie-try-block gebruikt of niet, is een implementatiedetail. Welke invloed heeft dit op de regels voor main ?
toegevoegd de auteur Kerrek SB, de bron
@MatthieuM. sinds het starten vanaf C ++ 11, = standaard , = verwijderen , {...} en proberen {...} vangen ... zijn allemaal vormen van functie-instantie , waarvan de specificatie zegt dat het informeel gebruikt wordt van "het lichaam van een functie X", ik stem sterk voor het interpreteren van de specificatie om te betekenen dat een catch-blok van een functie de standaardwaarden blokkeert naar return 0; .
toegevoegd de auteur Johannes Schaub - litb, de bron
Legaal? Technisch zullen de meeste compilers dit ondersteunen. Goed omschreven? Niet echt, want ik kan zeker geen goede reden bedenken om dit te doen.
toegevoegd de auteur AJG85, de bron
@awoodland: Een bron in dat geval toen je wees op de standaard zegt niet veel op één of andere manier. Het wordt overgelaten aan de compiler-implementatie en zal dus sterk variëren.
toegevoegd de auteur AJG85, de bron
@awoodland: worden alle compiler-uitbreidingen voor elke bekende geïmplementeerde omgeving vermeld? Ik vermoed dat er een aantal veronderstellingen zijn die worden benut om zoiets te ondersteunen. Ik kan echter niets vinden dat hier expliciet mee te maken heeft.
toegevoegd de auteur AJG85, de bron
Interessante academische vraag, hoewel ik niet zeker ben dat het veel praktisch nut heeft. stackoverflow.com/a/620817/10077
toegevoegd de auteur Fred Larson, de bron
@KerrekSB - De exacte vraag is "moet elke conforme implementatie int main() try {//...?" - een manier om te bewijzen dat het is toegestaan ​​als een functie-try-blok slechts een implementatiedetail is en main geen speciaal geval is. Het tegenovergestelde bewijs zou een expliciete regel voor main zijn.
toegevoegd de auteur Flexo, de bron
@GigaWatt - door mijn lezing is het waarschijnlijk goed, het is prima in het algemene geval en er zijn geen speciale case-regels die ik heb gevonden die erop van toepassing zijn. Het is de afwezigheid van een speciale hoofdregel voor main die me echter verbaasde.
toegevoegd de auteur Flexo, de bron
@ AJG85 - als het aan de compiler wordt overgelaten, wordt de implementatie gedefinieerd en bevindt deze zich in de "Index van door de implementatie gedefinieerd gedrag" aan de achterkant van de standaard.
toegevoegd de auteur Flexo, de bron
@ AJG85 - Ik bedoelde goed gedefinieerd in de zin van "niet aanroepen van niet-gedefinieerd gedrag, noch door implementatie gedefinieerd gedrag", niet in de "goed getest in gemeenschappelijke implementaties" manier
toegevoegd de auteur Flexo, de bron

2 antwoord

De standaard verbiedt het gebruik niet binnen [basic.start.main] en dwingt alle implementaties om tenminste int main() {/*...*/} en te ondersteunen int main (int argc, char * argv []) {/*...*/}, beperkt de implementaties niet tot die twee verklaringen (3.6.1, par. 2).

Van dat afgezonderde lijkt het op zijn minst dat het legaal is, hoewel dat natuurlijk alleen betrekking heeft op functie-verklaringen, niet op functie-definities.

Bij lezing, [behalve.handv], stelt paragraaf 13 het volgende:

Uitzonderingen weggegooid in destructors van objecten met statische opslag   duur of in constructors van naamruimte-scope-objecten worden niet gepakt   door een functie-try-block op main (). (15.3 par. 13)

It makes specific mention of a function-try-block placed on main(), which strongly implies that such a structure is legal and has defined behavior. Adding in the information that main() is only special in its name and return type, and that implementations may not overload it to alter any behavior, makes a pretty strong case that it acts in a normal fashion except when specially noted such as in the above quote. In other words, yes, it is legal and well-defined.

Het blogbericht dat ik in de eerste versie van dit antwoord heb verstrekt, is een goede illustratie van de regels die worden gegeven door het bovenstaande blockquote, dus ik zal behoud de link ernaar , ook al wordt het probleem niet rechtstreeks besproken in de vraag van het OP.

Met betrekking tot een opmerking over het OP kunt u retourinstructies afgeven binnen een functie-try-block , en [except.handle] heeft dit te zeggen:

Uit het einde van een functie vloeien-try-block is gelijk aan een return   zonder waarde; dit resulteert in ongedefinieerd gedrag in een waarde-retournering   functie (6.6.3). (15.3 par. 15)

Als je aan het einde van main in een catch-block zit, stroom je niet over het lichaam van de functie (wat in dit geval het try-blok zou zijn), dus de regel dat main roept automatisch return 0 aan; op flowover is niet van toepassing. Je moet wat int (mogelijk een foutcode) retourneren om niet ongedefinieerd te worden.

7
toegevoegd
Niet veel informatie (over de gedefinieerde waarden), de statische constataties zijn tamelijk eenvoudig: "globale" objecten worden geïnitialiseerd voordat hoofd wordt aangeroepen en vernietigd nadat het is geretourneerd ... dus uiteraard niet binnen het blok try/catch . Wat betreft de opmerkingen over de constructorsyntaxis, ja het is raar, maar geeft ook niet echt antwoord op de vraag ...
toegevoegd de auteur Matthieu M., de bron
Vanaf c ++ 11 is een functiontryblock een functie-instantie :-)
toegevoegd de auteur Johannes Schaub - litb, de bron
Zeg je dat alle impl's een functie try-blok moeten accepteren, of zeg je dat impls alleen toegestaan ​​zijn om een ​​functie-try-block te accepteren (of af te wijzen)?
toegevoegd de auteur Johannes Schaub - litb, de bron
Mijn antwoord verwijderen .. moet je thuis thuis onderzoeken ... maar wat is het nut van het geven van twee vereiste-om-te-accepteren definities van main, zo niet met de implicatie dat alle andere definitievormen niet vereist om te werken?
toegevoegd de auteur Johannes Schaub - litb, de bron
Dat citaat van 15,3 is best interessant. (Dat zou mogelijk mijn volgende vraag zijn als het legaal was) Gecombineerd met de DR waar Johannes mee verbonden is, lijkt het erop te antwoorden als toegestaan.
toegevoegd de auteur Flexo, de bron
Ik ben het met die beoordeling eens en heb het opgemerkt; bedankt. Ik vond een expliciete verwijzing naar main() met function-try-blocks, dus ik denk dat het artikel sowieso vrij nutteloos is. Ik zal een bewerking maken om dit te verduidelijken.
toegevoegd de auteur matthias, de bron
Het definiëren van twee must-accept-definities stolt twee minimale-functionaliteit "best practices" waarvan ontwikkelaars kunnen weten dat ze compatibel kunnen zijn (anders zouden verschillende compiler-leveranciers allemaal hun eigen speciale manier kunnen ontwikkelen om args af te handelen), terwijl leveranciers kunnen experimenteren met nieuwe ideeën als tech vordert. De standaard kan nieuwe, bewezen goede ideeën toevoegen aan toekomstige edities zonder al te veel verbazing. Stel u een platform voor dat u toelaat om te registreren voor geaccepteerde argumenten (al LLVM's CommandLine lib) en deze voor u heeft geparseerd voor main als een complexer object dan char * [] .
toegevoegd de auteur matthias, de bron
@awoodland: Na erover na te denken, ben ik er vrij zeker van dat 15.3 p.15 niet eens in de plaats hoeft te komen van hoofd 's auto- return 0; . In een dergelijk geval is het try-blok het lichaam van de functie en je zult duidelijk niet het einde van het lichaam bereiken als je gegooid/gevangen hebt. main is niets bijzonders, behalve als dit expliciet wordt vermeld, dus je moet een int van een soort terugsturen binnen het catch-block.
toegevoegd de auteur matthias, de bron
Gebaseerd op het feit dat de standaard specifiek een bepaald gedrag van een functie-try-block op main definieert, zou ik zeggen dat alle impls het moeten accepteren. Bovendien is het niet eens echt een probleem met functieverklaringen; door de standaard kan elke functiedefinitie een functie-try-block gebruiken in plaats van een function-body (8.4 par. 1).
toegevoegd de auteur matthias, de bron
Oh uitstekend! Ik werk aan een kopie uit 2005 en vroeg me eigenlijk af waarom het een verschil maakte tussen de twee. Ik zou de 11 standaard moeten pakken en alles dubbel controleren - ik betwijfel of iets op betekenisvolle wijze is veranderd, maar op zijn minst zijn mijn sectienummers nu misschien verkeerd.
toegevoegd de auteur matthias, de bron

Ik heb het geprobeerd, het compileert en het werkt zoals verwacht. Een eigenaardige formulering, maar ik denk niet dat het regels verbreekt. Voor de duidelijkheid (voor jezelf en toekomstige code-mantainers), zou je het ook kunnen herformuleren als:

int main() 
{
    try {
      throw 42;
    }
    catch( int /*...*/) {
    }
}
0
toegevoegd
Het werkt ook op mijn compiler. Het probleem met "het compileert en draait" is, ik weet dat mijn compiler compileert en een heleboel dingen uitvoert die niet goed gedefinieerd zijn.
toegevoegd de auteur Flexo, de bron
Redelijk punt, @awoodland. Dus, bij twijfel, zou ik willen voorstellen de formulering te gebruiken die ik hierboven noemde, die precies lijkt te doen wat u nodig heeft. Je oorspronkelijke formulering lijkt echter geen regels te overtreden van de standaard.
toegevoegd de auteur alexandreC, de bron