Gast
#6446989
Ich habe einen Vector:
1 | |
2 | |
3 | |
4 | |
und nun frage ich mich was ist der Unterschied zwischen diesen beiden Formen:
1 | |
|
Anzeige
|
c++ std::vector at(i) or [i]
Gast
#6446989
Ich habe einen Vector:
und nun frage ich mich was ist der Unterschied zwischen diesen beiden Formen:
Gast
#6446998
vector.at wirft eine Exception, wenn ein unzulässiger Index übergeben wird und der []-Operator tut das nicht.
Gast
#6447002
Perfekt, danke!
Gast
#6447054
stdvector schrieb: > Perfekt, danke Das perfekt ist anders gemeint, aber das ist wirklich das perfekte Konstrukt sich ins Knie zu schiessen. Ich nutzte C++ wirklich gerne, aber warum man nicht den default Weg abgesichert hat ist mir ein Rätsel. Den wirklich jeder Anfänger rennt irgendwann in diese Falle. Klaus schrieb: > warum man nicht den default Weg abgesichert hat Weil dann die alten C-Profi-Helden über die Kindergartensprache geheult hätten, die mit ihren unnötigen Features die Performance ausbremst. Ach je, in eine Falle rennt man als Anfänger vielleicht (ganz bestimmt) bei std::map, aber doch nicht beim vector. at() ist mit bounds checking, operator[] ohne. Das gilt für alle Container, und auch für das einfache C-Array ( das hat halt kein at() ). Foolproof ist keine Programmiersprache, man sollte immer wissen, was man tut. Oliver Klaus schrieb: > Das perfekt ist anders gemeint, aber das ist wirklich > das perfekte Konstrukt sich ins Knie zu schiessen. Vielleicht weil Du in einer expliziten for-loop mit Indizierung iterierst ...? Klaus schrieb: > stdvector schrieb: >> Perfekt, danke > > Das perfekt ist anders gemeint, aber das ist wirklich > das perfekte Konstrukt sich ins Knie zu schiessen. > > Ich nutzte C++ wirklich gerne, > aber warum man nicht den default Weg abgesichert hat ist mir ein Rätsel. > > Den wirklich jeder Anfänger rennt irgendwann in diese Falle. C++ hat viele Probleme, aber das ist keins davon. Der Weg, den man intuitiv wählt, also operator[], ist der schnelle. Wenn man sich für die Out-of-Bounds-Bedingung interessiert, wird man als Anfänger ja kaum aus dem Kopf "catch (std::out_of_range)" hinschreiben, sondern einen Blick in die Doku werfen. Wo das dann alles steht.
Beitrag #6449309 wurde von einem Moderator gelöscht.
Gast
#6449336
Heiner schrieb: > vector.at wirft eine Exception, wenn ein unzulässiger Index übergeben > wird und der []-Operator tut das nicht. Auch operator[] darf eine Exception werfen, wenn ein Out-of-Bounds Zugriff erfolgt.
Gast
#6449338
Wilhelm M. schrieb: > Vielleicht weil Du in einer expliziten for-loop mit Indizierung > iterierst ...? Nein, einfach weil ich ein Freund defensiver Vorgehensweisen bin. Ich weiss ja, dass Security bei der Erstellung der STL nicht im Bewustsein war. Aber umgekehrt, sprich at() ohne Prüfung, waere mir persönlich lieber gewesen. Ich nutze vor Jahren einen C Compiler der Boundary check konnte. Reihenweise ist Code des Teams in Ausnahmen gerannt. Heutzutage mit TDD vermutlich weniger wichtig. Ist aber nur meine persönliche Meinung. Ich kann damit Leben. mh schrieb: > Heiner schrieb: >> vector.at wirft eine Exception, wenn ein unzulässiger Index übergeben >> wird und der []-Operator tut das nicht. > > Auch operator[] darf eine Exception werfen, wenn ein Out-of-Bounds > Zugriff erfolgt. Auszug aus cppreference: --- Returns a reference to the element at specified location pos. No bounds checking is performed. Notes Unlike std::map::operator[], this operator never inserts a new element into the container. Accessing a nonexistent element through this operator is undefined behavior. --- Ich denke, das ist unmissverständlich. Wilhelm M. schrieb: > Ich denke, das ist unmissverständlich. Ja, wobei das hier nicht so ganz stimmt: > No bounds checking is performed. Es ist der Standardlib nicht verboten, bounds checking zu machen. Man sollte als Programmierer nur nicht davon ausgehen, dass es gemacht wird. > Accessing a nonexistent element through this operator is undefined behavior. "undefined behavior" heißt, dass der C++-Standard keinerlei Vorgaben dazu macht, was in diesem Fall passiert. Wenn der Entwickler der Standardbibliothek sich dazu entscheidet, in dem Fall eine out-of-bounds-Exception zu werfen, verstößt er damit nicht gegen den Standard. Rolf M. schrieb: > Wilhelm M. schrieb: >> Ich denke, das ist unmissverständlich. > > Ja, wobei das hier nicht so ganz stimmt: > >> No bounds checking is performed. > > Es ist der Standardlib nicht verboten, bounds checking zu machen. Man > sollte als Programmierer nur nicht davon ausgehen, dass es gemacht wird. Sehe ich anders: hier ist kein Freiraum für eine Implementierung. > >> Accessing a nonexistent element through this operator is undefined behavior. > > "undefined behavior" heißt, dass der C++-Standard keinerlei Vorgaben > dazu macht, was in diesem Fall passiert. Nein, das wäre implementation-defined. Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, sondern klar definiert, was passiert, allerdings außerhalb der Festlegungen des Standard. Wilhelm M. schrieb: > Nein, das wäre implementation-defined. > Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, Je nun, diese Diskussion,was "undefined behaviour" ist, ist müßig. Natürlich darf die lib da eine Exception werfen, oder die Anwendung terminieren, oder "out of bounds" nach stderr schreiben, oder die Festplatte formatieren. Man darf sich nur nicht drauf verlassen... libstdc++ bietet z.B debug-Versionen der Container, (-D_GLIBCXX_DEBUG), die dann operator[] bounds-cheking haben. Oliver Wilhelm M. schrieb: > Sehe ich anders: hier ist kein Freiraum für eine Implementierung. Genau das Gegenteil ist der Fall: Der Freiraum für die Implementierung ist unendlich groß. Genau das heißt "undefined behavior". Aber gut: Wenn der Compiler keinen Freiraum hat, was ist denn deiner Meinung nach das Verhalten, das laut Standard passieren muss, wenn man einen out-of-Bounds-Zugriff auf einen vector per operator[] versucht? >> "undefined behavior" heißt, dass der C++-Standard keinerlei Vorgaben >> dazu macht, was in diesem Fall passiert. > > Nein, das wäre implementation-defined. Implementation-defined heißt, dass für den Compiler ein Verhalten definiert und dokumentiert sein muss. > Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, Doch, denn undefined behavior heißt, dass JEDES Verhalten korrekt ist, und das beinhaltet auch das Werfen einer Exception. > sondern klar definiert, was passiert, allerdings außerhalb der > Festlegungen des Standard. "undefined" bezieht sich auf den Standard - das Verhalten ist nicht durch den Standard definiert. Der Compiler darf machen, was er will - auch ein Verhalten definieren. Er muss aber nicht. Der Compiler wird nicht dazu gezwungen, irgendetwas unvorhersehbares zu tun.
Gast
#6449525
Wilhelm M. schrieb: > Returns a reference to the element at specified location pos. No bounds > checking is performed. > Ich denke, das ist unmissverständlich. cppref ist unmissverständlich, aber wo steht das im Standard? Ich kann dort nur finden, dass at() einen Check durchführt, nichts zu operator[]. Ich habe explizit geschrieben, dass eine Exception geworfen wird, nichts von einem Check. Da, wie Rolf M. geschrieben hat, das behavior undefined ist, ist das auch zulässig, falls der Standard den Check verbietet. Wilhelm M. schrieb: > Nein, das wäre implementation-defined. > Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, > sondern klar definiert, was passiert, allerdings außerhalb der > Festlegungen des Standard. "Implementation defined" ist im C++ Standard die Festlegung, dass die Implementation an der Stelle ein definiertes und dokumentiertes Verhalten haben muss. Dein Compilerhersteller würde also verpflichtet in die Doku zu schreiben, wass passiert, wenn ein out of bounds Zugriff passiert und das auch konsequent umzusetzen. "Undefined" schreibt das eben nicht vor, Compiler/Bibliothek dürfen machen, was sie wollen, inkl. ihr Verhalten festzulegen und zu dokumentieren. Rolf M. schrieb: > Wilhelm M. schrieb: >> Sehe ich anders: hier ist kein Freiraum für eine Implementierung. > > Genau das Gegenteil ist der Fall: Der Freiraum für die Implementierung > ist unendlich groß. Genau das heißt "undefined behavior". Es steht dort: no bounds checking. Daher darf das dort auch nicht ausgeführt werden. Kein Freiraum für eine Implementierung. Rolf M. schrieb: > Implementation-defined heißt, dass für den Compiler ein Verhalten > definiert und dokumentiert sein muss. Genau. >> Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, > > Doch, denn undefined behavior heißt, dass JEDES Verhalten korrekt ist, > und das beinhaltet auch das Werfen einer Exception. Ok, überzeugt: wenn dort UB steht, dann darf der Hersteller das durch IB erstzen, muss aber nicht. Nur wenn dort IB steht, muss er ein IB beschreiben. Allerdings könnte der Compiler einen Zugriff auf ein std::Array außerhalb dessen Größe schlicht wegoptimieren (und eventuell noch viel mehr, was halt bei UB alles so passieren kann), wenn er das erkennen kann. Ob er das kann, kann ich allerdings nicht sagen. Da käme die lib gar nicht mehr dazu, die exception zu werfen. Oliver Wilhelm M. schrieb: > Rolf M. schrieb: >> Implementation-defined heißt, dass für den Compiler ein Verhalten >> definiert und dokumentiert sein muss. > > Genau. > >>> Bei einem bounds-checking / throw wäre es kein undefined-bevaiour, >> >> Doch, denn undefined behavior heißt, dass JEDES Verhalten korrekt ist, >> und das beinhaltet auch das Werfen einer Exception. > > Ok, überzeugt: wenn dort UB steht, dann darf der Hersteller das durch IB > erstzen, muss aber nicht. Noch nicht ganz. Die Bezeichnungen beziehen sich auf den Standard selbst, nicht auf den Compiler. Undefined behavior heißt, dass der Standard das Verhalten nicht definiert und keinerlei Vorgaben dazu macht, was passiert. Implementation-defined behavior heißt, dass der Standard von der Implementation verlangt, dass sie es definiert (und dokumentiert). Wenn etwas UB ist, bleibt es also UB, auch wenn der Compiler das Verhalten definiert. Rolf M. schrieb: >> Ok, überzeugt: wenn dort UB steht, dann darf der Hersteller das durch IB >> erstzen, muss aber nicht. > > Noch nicht ganz. Die Bezeichnungen beziehen sich auf den Standard > selbst, nicht auf den Compiler. Undefined behavior heißt, dass der > Standard das Verhalten nicht definiert. Implementation-defined behavior > heißt, dass der Standard von der Implementation verlangt, dass sie es > definiert (und dokumentiert). > Wenn etwas UB ist, bleibt es also UB, auch wenn der Compiler das > Verhalten definiert. Genau so war es gemeint. Denn wo der Standard von UB spricht, kann es im Sinne des Standards kein IB geben.
Gast
#6450991
Manche Diskussionen verstehe ich nicht.... mh schrieb: > Auch operator[] darf eine Exception werfen, wenn ein Out-of-Bounds > Zugriff erfolgt. Könnte, aber macht in diesem Zusammenhang keinen Sinn. Klaus schrieb: > Ich weiss ja, dass Security bei der Erstellung der STL nicht im > Bewustsein war. Naja... Ist es nicht klar, was die vector Entwickler sich dabei gedacht haben? Dann hier zum mitmeißeln: Eins der oberen Entwicklungsziele war: Performance Das lässt sich mit Bereichsprüfungen zu Laufzeit nicht realisieren und genau in einer solchen zeitkritischen Situation sollen diese Container weiter verwendbar sein. Aus dem Grund wird eine schnelle und eine sichere (Zugriffs-) Variante angeboten. Fakt: Wenn gesichert ist, dass die Bereichsgrenzen nicht überschritten werden, besteht kein Grund für weitere Laufzeitprüfungen. Klar kann man sich ins Knie schießen, wenn man das nicht weiß/beachtet.
Gast
#6451008
Arduino Fanboy D. schrieb: > Ist es nicht klar, was die vector Entwickler sich dabei gedacht haben? Dann denk mal ein paar Meter weiter. Was ist mit dem std::vector, der im Debug-Mode die Grenzen überprüfen soll und im Relese nicht. Was machst du dann? Schreibst du eine Fallunterscheidung in deine Anwendung ein, um im Debug-Mode at statt [] zu nutzen? mh schrieb: > Arduino Fanboy D. schrieb: >> Ist es nicht klar, was die vector Entwickler sich dabei gedacht haben? > > Dann denk mal ein paar Meter weiter. Was ist mit dem std::vector, der im > Debug-Mode die Grenzen überprüfen soll und im Relese nicht. Was machst > du dann? Schreibst du eine Fallunterscheidung in deine Anwendung ein, um > im Debug-Mode at statt [] zu nutzen? Entweder Debug-Mode der libstdc++ oder die Container parametrierbar halten, und dann ggf. einen anderen oder einen Wrapper verwenden.
Gast
#6451064
mh schrieb: > Dann denk mal ein paar Meter weiter. Ich habe dir gesagt, was sich die Entwickler dabei gedacht haben, und nicht was ich davon halte. Aber wenn du es unbedingt wissen willst: Ich stimme den Entwicklern zu! Performance und Sicherheit schließen sich in dem Fall gegenseitig aus. Vergleich: Du kommst mir vor, wie jemand, welcher gleichzeitig durch 2 Türen, aus einem Auto aussteigen will, und weil er das nicht hin bekommt, über die überflüssige Tür schimpft. (und in der Folge, im Auto verhungert) Siehe: Buridans Esel
Gast
#6451076
Oliver S. schrieb: > Allerdings könnte der Compiler einen Zugriff auf ein std::Array > außerhalb dessen Größe schlicht wegoptimieren (und eventuell noch viel > mehr, was halt bei UB alles so passieren kann), wenn er das erkennen > kann. Ob er das kann, kann ich allerdings nicht sagen. > Da käme die lib gar nicht mehr dazu, die exception zu werfen. Schau dir mal std::get<N>(std::array) an. Dann kompiliert dein zur Kompilierzeit bekannter aber out-of-bounds-Zugriff erst gar nicht. https://en.cppreference.com/w/cpp/container/array/get Ben Gunn schrieb: > Oliver S. schrieb: >> Allerdings könnte der Compiler einen Zugriff auf ein std::Array >> außerhalb dessen Größe schlicht wegoptimieren (und eventuell noch viel >> mehr, was halt bei UB alles so passieren kann), wenn er das erkennen >> kann. Ob er das kann, kann ich allerdings nicht sagen. >> Da käme die lib gar nicht mehr dazu, die exception zu werfen. > > Schau dir mal std::get<N>(std::array) an. Dann kompiliert dein zur > Kompilierzeit bekannter aber out-of-bounds-Zugriff erst gar nicht. > > https://en.cppreference.com/w/cpp/container/array/get Das ist trivial, aber hier nicht gemeint: siehe Eingangspost.
Gast
#6451130
Wilhelm M. schrieb: > mh schrieb: >> Arduino Fanboy D. schrieb: >>> Ist es nicht klar, was die vector Entwickler sich dabei gedacht haben? >> >> Dann denk mal ein paar Meter weiter. Was ist mit dem std::vector, der im >> Debug-Mode die Grenzen überprüfen soll und im Relese nicht. Was machst >> du dann? Schreibst du eine Fallunterscheidung in deine Anwendung ein, um >> im Debug-Mode at statt [] zu nutzen? > > Entweder Debug-Mode der libstdc++ oder die Container parametrierbar > halten, und dann ggf. einen anderen oder einen Wrapper verwenden. Damit handelt man sich aber ne ganze Menge mehr Komplexität ein, als ein einfaches
oder
im operator[]. Ich glaube libcxx macht sowas. Arduino Fanboy D. schrieb: > mh schrieb: >> Dann denk mal ein paar Meter weiter. > > Ich habe dir gesagt, was sich die Entwickler dabei gedacht haben, und > nicht was ich davon halte. Wenn es das ist was sich die Entwickler dabei gedacht haben, warum wird der Check dann nicht explizit verboten im Standard und warum ist operator[] dann noexcept? Du musst das ja beantworten können, du weißt ja, was die Entwickler denken. > Aber wenn du es unbedingt wissen willst: > Ich stimme den Entwicklern zu! > > Performance und Sicherheit schließen sich in dem Fall gegenseitig aus. Das kommt darauf an, wie du Performance und Sicherheit definierst. Bei mir schließt sich das hier nicht aus. mh schrieb: > Damit handelt man sich aber ne ganze Menge mehr Komplexität ein, als ein > einfaches Nein, null overhead. bzw. genausoviel Overhead (wie nötig) und in Deiner Lösung. Nur ohne Präprozessor und total flexibel.
Gast
#6451145
Wilhelm M. schrieb: > Nein, null overhead. bzw. genausoviel Overhead (wie nötig) und in Deiner > Lösung. Nur ohne Präprozessor und total flexibel. Ich habe nicht Overhead, sondern Komplexität geschrieben. Das ist ein Unterschied. Das ist der zweite Satz, der in libstdc++ Doku unter "Using the Debug Mode" steht.
Gast
#6451201
mh schrieb: > Wenn es das ist was sich die Entwickler dabei gedacht haben, warum wird > der Check dann nicht explizit verboten im Standard und warum ist > operator[] dann noexcept? Du musst das ja beantworten können, du weißt > ja, was die Entwickler denken. Das ist ein bisschen Problematisch zu beantworten, da die Argumentation längst nicht nur auf die std Container zutrifft. Einerseits hat noexcept einen dokumentierenden Charakter und andererseits erlaubt es weiter gehende (automatische) Optimierungen. Es ist also schon der Performance zuträglich, welches ja eins der Design Ziele ist. mh schrieb: >> Performance und Sicherheit schließen sich in dem Fall gegenseitig aus. > Das kommt darauf an, wie du Performance und Sicherheit definierst. Bei > mir schließt sich das hier nicht aus. Interessant! Da scheinst du recht eigenwillige Definitionen zu haben. Aber ok... jedem sein Himmelreich.
Gast
#6451216
Arduino Fanboy D. schrieb: > mh schrieb: >> Wenn es das ist was sich die Entwickler dabei gedacht haben, warum wird >> der Check dann nicht explizit verboten im Standard und warum ist >> operator[] dann noexcept? Du musst das ja beantworten können, du weißt >> ja, was die Entwickler denken. > Das ist ein bisschen Problematisch zu beantworten, da die Argumentation > längst nicht nur auf die std Container zutrifft. Ich formuliere es nochmal etwas genauer. - Warum verbietet der Standard den Bound-Check für std::vector::operator[] weder explizit noch implizit? - Warum verlangt der Standerd kein noexcept für std::vector::operator[]? Arduino Fanboy D. schrieb: > mh schrieb: >>> Performance und Sicherheit schließen sich in dem Fall gegenseitig aus. >> Das kommt darauf an, wie du Performance und Sicherheit definierst. Bei >> mir schließt sich das hier nicht aus. > Interessant! > Da scheinst du recht eigenwillige Definitionen zu haben. > Aber ok... jedem sein Himmelreich. Was genau ist hier dein Problem? Ich bekomme die Sicherheit im Debug-Build wenn ich explizit danach frage und die Performance im Release, ohne etwas in meiner Anwendung zu ändern. Wieso schließt sich das aus?
Gast
#6451385
mh schrieb: > Wieso schließt sich das aus? Weil du nicht aus 2 Türen gleichzeitig das Auto verlassen kannst. Mit dem "Debuggen" betrittst du einen dritten Weg. z.B. Machst mit der Flex ein Loch ins Dach. Die "Lösung" ist für die fertige Anwendung irrelevant. Betrifft also gar nicht die Entscheidung zwischen sicher und performant. mh schrieb: > - Warum verbietet der Standard den Bound-Check für > std::vector::operator[] weder explizit noch implizit? > > - Warum verlangt der Standerd kein noexcept für std::vector::operator[]? Der "Standard" verlangt eine einheitliche (minimal) Schnittstelle. Dazu gehört die "no-throw" Garantie für std::vector::operator[]. Die konkrete Implementierung darf sich unterscheiden. Solche Freiheiten finden sich noch an Hunderten weiteren Stellen so, oder so ähnlich. Warum der Standard da kein noexcept erwartet, kann ich dir nicht sagen. Allerdings leitet sich der Einsatz von noexcept für std::vector::operator[] eigentlich zwangsläufig aus der "no-throw" Garantie ab. Vielleicht kommt das ja noch. C++11 ist ja noch nicht so ganz alt. Arduino Fanboy D. schrieb: > Dazu gehört die "no-throw" Garantie für std::vector::operator[]. Wer garantiert dir das? Oliver
Gast
#6451439
Oliver S. schrieb: > Arduino Fanboy D. schrieb: >> Dazu gehört die "no-throw" Garantie für std::vector::operator[]. > Wer garantiert dir das? ? seltsame Frage... Der "Standard" fordert es ein. Der Implementierer hat es umzusetzen. Dann mal etwas deutlicher: wo im Standard steht die generelle nothrow-Garantie für den operator[]? Ich zitiere mal das, was cplusplus.com dazu schreibt:
Die sind allerdings nicht die normative Referenz, daher hätte ich gerne dazu eine Link auf eine Originalquelle. Oliver
Gast
#6451494
https://en.cppreference.com/w/cpp/named_req/SequenceContainer http://www.open-std.org/jtc1/sc22/open/n2356/lib-containers.html#lib.sequence.reqmts
Gast
#6451504
Oliver S. schrieb: > Die sind allerdings nicht die normative Referenz, daher hätte ich gerne > dazu eine Link auf eine Originalquelle. https://isocpp.org/files/papers/N4860.pdf std::vector ab 22.3.11, PDF-Seite 852ff, Seitennummer 840ff
Da steht kein noexcept.
Bei 22.2.3 "Sequence containers", clause 15:
> The member function at() provides bounds-checked access to container elements.
at() throws out_of_range if n >= a.size().
Gast
#6451510
Al Fine schrieb: > https://en.cppreference.com/w/cpp/named_req/SequenceContainer > http://www.open-std.org/jtc1/sc22/open/n2356/lib-containers.html#lib.sequence.reqmts Ben Gunn schrieb: > Da steht kein noexcept. Da steht außer der Signatur überhaupt nichts zum operator[] drin. Das ist dann noch weniger, als ich vermutet habe. Es steht ansonsten nur drin, daß at() bounds checking durchführt. Oliver
Gast
#6451529
using V = std::vector<int>; static_assert(noexcept(std::declval<V>()[0]));
Gast
#6451678
Arduino Fanboy D. schrieb: > mh schrieb: >> Wieso schließt sich das aus? > Weil du nicht aus 2 Türen gleichzeitig das Auto verlassen kannst. Mach mit deinen Türen was du willst. Die Analogie ist zu dämlich, um darauf sinnvoll zu antworten. Arduino Fanboy D. schrieb: > Warum der Standard da kein noexcept erwartet, kann ich dir nicht sagen. > Allerdings leitet sich der Einsatz von noexcept für > std::vector::operator[] eigentlich zwangsläufig aus der "no-throw" > Garantie ab. > Vielleicht kommt das ja noch. C++11 ist ja noch nicht so ganz alt. Wie schon mehrfach gefragt, wo steht im Standard etwas von dieser Garantie? Was der Standard von std::vector::operator[] fordert steht in dieser Tabelle in der vorletzten Zeile. http://eel.is/c++draft/tab:container.seq.opt Ich zitiere nochmal aus deinem vorherigen Beitrag: Arduino Fanboy D. schrieb: > Ich habe dir gesagt, was sich die Entwickler dabei gedacht haben, und > nicht was ich davon halte. Wir haben also festgestellt, dass du keine Ahnung hast, was sich die Entwickler dabei gedacht haben. Du hast nichtmal einen Blick in den Standard (das Ergebnis ihre Gedanken) geworfen.
Gast
#6451695
mh schrieb: > Was der Standard von std::vector::operator[] fordert steht in dieser > Tabelle in der vorletzten Zeile. > http://eel.is/c++draft/tab:container.seq.opt (a[i] <=> *(a.begin() + i)) ^ (noexcept(*(a.begin() + i)) == true) => noexcept(a[i]) == true Kommt nicht ganz hin: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf "... left as a library vendor quality-of-implementation feature ..." Schließlich müsste man bei Tests sonst einen Signal-Handler bemühen. Ex falso quodlibet - das Programm in der Situation sowieso alles machen.
Gast
#6451754
Kaum ist man Mal ein paar Stunden weg... Ihr bestätigt eigentlich nur meine Meinung, dass die Lösung so sehr fehleranfällig ist und selbst erfahrene Programmierer am Ende über IB / UB stolpern. Und falls das falsch rüber kam: Natürlich ist es sinnvoll dass es einen performanten schnellen Zugriff gibt. Aber den hätte man über at() lösen können und den sicheren definierten Zugriff über []. Hätte keinem Weh getan und einige C++ Programme währen robuster. Al Fine schrieb: > using V = std::vector<int>; > static_assert(noexcept(std::declval<V>()[0])); Die gcc libc++ implementiert das so, aber das ist eben nur deren Interpretation des Standards.
Oliver
Gast
#6451775
Klaus schrieb: > Aber den hätte man über at() lösen können und den sicheren definierten > Zugriff über []. > > Hätte keinem Weh getan und einige C++ Programme währen robuster. Aber warum sollte man es noch schwieriger und mühsamer machen, performanten Code zu schreiben? Die bei der Performance gesparte Mühe kann man doch besser da in die Tipparbeit und die nötigen extra Fallunterscheidungen bei templatisiertem Zugriff über [] investieren.
Gast
#6451778
Al Fine schrieb: > Aber warum sollte man es noch schwieriger und mühsamer machen, > performanten Code zu schreiben? Ist es doch gar nicht. At() und [] unterscheiden sich in 2 Buchstaben... Man muss bei der Diskussion dran denken, das die Standardisierung zu anderen Zeiten war. Heute sind Compiler deutlich mächtiger und könnten einiges optimieren. Viele Codierstandards fordert Defensive Programmierung. Das ist wichtig. Was bringt mir ein Programm das performant ist und beim ersten Zugriff undefiniert aussteigt? Schlechte Performance sieht man sofort und kam dann optimieren. Schlechte Robustheit passiert erst im Ernstfall. Welches ist der kritische Fall...?
Gast
#6451784
Klaus schrieb: > At() und [] unterscheiden sich in 2 Buchstaben... Na, wenn das für dich der Unterschied ist, kannst du ja at() verwenden. No problem at all.
Gast
#6451794
Mach ich. Ich hab's ja verstanden und bei mir geht Sicherheit vor Performance. Ich hatte nur das meiner Meinung nach schlechte Design "Performances vor Sicherheit" kritisiert. Iss so, ich lebe damit. Aber es fällt mir bei Code Reviews immer wieder auf. Warum meckern viele über strcpy? Ist doch performanter als strncpy...? 😀
Gast
#6451797
Klaus schrieb: > Warum meckern viele über strcpy? > Ist doch performanter als strncpy...? Ja - und warum sollte man keines von beidem verwenden?
Gast
#6451798
Al Fine schrieb: > Klaus schrieb: >> Warum meckern viele über strcpy? >> Ist doch performanter als strncpy...? > > Ja - und warum sollte man keines von beiden verwenden?
Gast
#6451812
siehst du, du bist in die Falle getappt: man nimmt natürlich strlcpy. Aber warum pochst du bei str copies auf Sicherheit und bei [] vector operator nicht? das ist nicht konsequent. Daher meine Regel: Immer defensiv, nur bei Performance Problemen darauf verzichten. Wünsche gute Nacht.
Gast
#6451813
Klaus schrieb: > Aber warum pochst du bei str copies auf Sicherheit und bei [] vector > operator nicht? das ist nicht konsequent. Naja, wenn out-of-range behaviour das ist, was ein Argument für strncpy oder strcpy abgibt, macht vermutlich keine der beiden Funktionen genau das, was man eigentlich haben wollte.
Gast
#6451822
Al Fine schrieb: > mh schrieb: >> Was der Standard von std::vector::operator[] fordert steht in dieser >> Tabelle in der vorletzten Zeile. >> http://eel.is/c++draft/tab:container.seq.opt > > (a[i] <=> *(a.begin() + i)) ^ (noexcept(*(a.begin() + i)) == true) > => noexcept(a[i]) == true > > Kommt nicht ganz hin: > http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3279.pdf > > "... left as a library vendor quality-of-implementation feature ..." > Schließlich müsste man bei Tests sonst einen Signal-Handler bemühen. > > Ex falso quodlibet - das Programm in der Situation sowieso alles machen. Was genau willst du sagen? Wo im Standard steht die von dir hier genannte noexcept Bedingung? In dem von dir verlinkten Dokument steht es nicht drin und wäre auch sonst nicht relevant, da es nicht Teil des Standards ist.
Gast
#6451823
mh schrieb: > Wo im Standard steht die von dir hier > genannte noexcept Bedingung? Die ist erschlossen anhand der von dir verlinkten Semantik des "a[i]". Wenn a[i] die semantische Bedeutung "*(a.begin() + i)" hat, was heisst das dann, wenn "a.begin()" noexcept ist? Oder meinst du eine mögliche exception ist keine semantische Abweichung?
Gast
#6451829
Al Fine schrieb: > Aber warum sollte man es noch schwieriger und mühsamer machen, > performanten Code zu schreiben? Wozu müssen selten ausgeführte Pfade (ergo der meiste Code) auf Performance optimiert werden? Der Unterschied zur sicheren Variante ist meist völlig insignifikant, wenn überhaupt messbar (besonders auf superskalaren Prozessoren). Genau dort die Sicherheit in irgendeiner Form aufwändiger zu machen schlägt sich ausschließlich in Sicherheitslücken nieder. Die Checks brauchst du natürlich nicht, weil dir nie Programmierfehler unterlaufen mit deinen goldenen Händchen, kennt man.
Gast
#6451873
Jemand schrieb: > Wozu müssen selten ausgeführte Pfade (ergo der meiste Code) auf > Performance optimiert werden? Volle Zustimmung. Genau dafür gibt es Performance Tools. Optimiert wird wenn man weiss wo man am effektivsten optimieren kann.
Gast
#6451991
Jemand schrieb: > Wozu müssen selten ausgeführte Pfade (ergo der meiste Code) auf > Performance optimiert werden? Wieso selten ausgeführt? Ich mache genau dann einen Bounds-Check, wenn ich den machen will und auch nur dann. Das hat mit Programmierfehlern nichts zu tun. Die standartisierten Klassen sind so designed, dass sie für möglichst viele use-cases brauchbar sind. Irgendwie gehört es dann dazu, dass sich Raw-Pointer, arrays und vectors in templateisiertem Code ohne größere Probleme austauschen lassen. Jemand schrieb: > Die Checks brauchst du natürlich nicht, weil dir nie Programmierfehler > unterlaufen mit deinen goldenen Händchen, kennt man. Danke. Nächster. Al Fine schrieb: > Die ist erschlossen anhand der von dir verlinkten Semantik des "a[i]". > Wenn a[i] die semantische Bedeutung "*(a.begin() + i)" hat, was heisst > das dann, wenn "a.begin()" noexcept ist? Nichts, da weder der Operator+, noch der Operator* des Iterators noexcept sein muss, und die sind auch der entscheidende Teil für die out-of-bounds-Prüfung. Es gibt überhaupt nur einen Fall, in dem das Ergebnis von begin() out-of-bounds ist, und das ist, wenn der Container leer ist. Da ist das aber kein Fehler, sondern so gedacht.
Gast
#6452263
Rolf M. schrieb: > Nichts, da weder der Operator+, noch der Operator* des Iterators > noexcept sein muss, und die sind auch der entscheidende Teil für die > out-of-bounds-Prüfung. Ja, gut... wenn dein + operator exceptions wirft, tut er das halt... Rolf M. schrieb: > Es gibt überhaupt nur einen Fall, in dem das Ergebnis von begin() > out-of-bounds ist, und das ist, wenn der Container leer ist. Da ist das > aber kein Fehler, sondern so gedacht. Falsch, begin() liefert einen iterator. Der ist immer gültig, aber nicht immer de-referenzierbar. Al Fine schrieb: > Falsch, Nein, richtig, nur von dir falsch interpretiert. > begin() liefert einen iterator. Der ist immer gültig, aber nicht > immer de-referenzierbar. Richtig, und wenn er nicht dereferenzierbar ist, ist er das, weil er out-of-bounds ist (verweist auf eins nach dem letzten Element).
Gast
#6452280
Rolf M. schrieb: > Al Fine schrieb: >> Falsch, > > Nein, richtig, nur von dir falsch interpretiert. > >> begin() liefert einen iterator. Der ist immer gültig, aber nicht >> immer de-referenzierbar. > > Richtig, und wenn er nicht dereferenzierbar ist, ist er das, weil er > out-of-bounds ist (verweist auf eins nach dem letzten Element). Ja, aber man kann den iterator beliebig inkrementieren und dekrementieren. Solange man ihn nicht dereferenziert gibt es da kein Problem. Im speziellen sollte keine Exception bei einem Ausdruck
fliegen. Auch dann nicht, wenn iter+X oob ist.
Gast
#6452282
Aber wie gesagt: Wenn deine Iteratoren das tun, dann tun sie das halt. :)
Gast
#6452285
Worum es die ganze Zeit geht: Es ist sinnlos, um ein a[i] ein try-catch zu bauen, [i]es sei denn[/i] man schreibt einen Test-Driver oder sowas. Über kaputten Code zu philosophieren ist müßig.
Gast
#6452301
Al Fine schrieb: > Ja, aber man kann den iterator beliebig inkrementieren und > dekrementieren. Solange man ihn nicht dereferenziert gibt es da kein > Problem. Im speziellen sollte keine Exception bei einem AusdrucknewIter > = iter + X - Y; > fliegen. Auch dann nicht, wenn iter+X oob ist. Wo steht diese Anforderung im Standard? Für Pointer gilt das z.B. nicht.
Gast
#6452303
mh schrieb: > Al Fine schrieb: >> Ja, aber man kann den iterator beliebig inkrementieren und >> dekrementieren. Solange man ihn nicht dereferenziert gibt es da kein >> Problem. Im speziellen sollte keine Exception bei einem AusdrucknewIter >> = iter + X - Y; >> fliegen. Auch dann nicht, wenn iter+X oob ist. > > Wo steht diese Anforderung im Standard? Für Pointer gilt das z.B. nicht. Sollte - nicht muss. Werde glücklich mit deinen Iteratoren, die das machen.
Gast
#6452322
Al Fine schrieb: > Sollte - nicht muss. Werde glücklich mit deinen Iteratoren, die das > machen. Das ist also deine persönliche Meinung?
Gast
#6452323
Ja, da muss man nicht groß diskutieren, denke ich. Wenn mit deinem Konzept schon ein range-for auseinanderfliegt - wozu der Worte. Mach du einfach...
Gast
#6452324
Und such das mal schön selbst im Standard! Al Fine schrieb: > mh schrieb: >> Wo im Standard steht die von dir hier >> genannte noexcept Bedingung? > > Die ist erschlossen anhand der von dir verlinkten Semantik des "a[i]". > Wenn a[i] die semantische Bedeutung "*(a.begin() + i)" hat, was heisst > das dann, wenn "a.begin()" noexcept ist? Oder meinst du eine mögliche > exception ist keine semantische Abweichung? a.begin() kann sein, was es will. Das entscheidende ist die Dereferenzierung. Wenn a.begin() + i hinter das Ende des Containers zeigt, dereferenzierst du mit *(a.begin() + i) einen not dereferencable iterator, und das ist undefined behaviour. Damit sind wir dann wieder ganz am Anfang dieses Threads, und können erneut diskutieren, ob UB auch nicht erwartete exceptions einschliesst. Oliver
Gast
#6452346
Al Fine schrieb: > Wenn mit deinem Konzept schon ein range-for auseinanderfliegt - wozu der > Worte. Mach du einfach... Warum fliegt welche range-for auseinander? Ein paar mehr erklärende Worte von dir wären schon hilfreich. mh schrieb: > Al Fine schrieb: >> Wenn mit deinem Konzept schon ein range-for auseinanderfliegt - wozu der >> Worte. Mach du einfach... > > Warum fliegt welche range-for auseinander? Ein paar mehr erklärende > Worte von dir wären schon hilfreich. Das würde mich auch interessieren. Zeigerarithmetik darf man nur innerhalb eines Arrays oder auf eins nach dessen Ende machen. Darüber hinaus ist das verboten, und zwar auch schon ohne Dereferenzierung. Da ein Zeiger auch als Random-Access-Iterator genutzt werden kann, würde ich vermuten, das für diese die gleichen Anforderungen gelten.
Gast
#6452698
Rolf M. schrieb: > Zeigerarithmetik darf man nur > innerhalb eines Arrays oder auf eins nach dessen Ende machen. Und genau da knallt es schon.
Gast
#6452701
Ich meine, es steht mh ja frei, das so zu machen. Wie ich zitierte Al Fine schrieb: > "... left as a library vendor quality-of-implementation feature ..." Wenn er die "Qualität: unbenutzbar" anstrebt, kann er das ja gerne machen. Kann std-konform sein....
Gast
#6452792
Al Fine schrieb: > Ich meine, es steht mh ja frei, das so zu machen. > > Wie ich zitierte > > Al Fine schrieb: >> "... left as a library vendor quality-of-implementation feature ..." > > Wenn er die "Qualität: unbenutzbar" anstrebt, kann er das ja gerne > machen. Kann std-konform sein.... Kannst du mal etwas genauer erklären was du meinst? Du musst hier nicht zwingend unter 140 Zeichen bleiben. Was steht mir frei "das so zu machen"? Warum soll was ich mache, was auch immer du meinst, unbenutzbar sein? Al Fine schrieb: > Rolf M. schrieb: >> Zeigerarithmetik darf man nur >> innerhalb eines Arrays oder auf eins nach dessen Ende machen. > > Und genau da knallt es schon. Wo knallt was?
Gast
#6452800
Weißt du... mach doch einfach einen eigenen Thread auf mit der Frage. Al Fine schrieb: > Weißt du... mach doch einfach einen eigenen Thread auf mit der Frage. Ok, du hast also einfach keinen Bock, dich verständlich auszudrücken. Warum soll er einen neuen Thread aufmachen, um dich zu fragen, wie du das meinst? Es bleibt weiterhin ein Rätsel, was das ominöse "das" sein soll, von dem du denkst, dass wir es tun und warum du glaubst, es müsse dann knallen.
Gast
#6453083
Steht alles oben. Lesen, denken, verstehen. Wenn ihr schlicht zu dämlich seid, einen deutschen Text zu lesen, kann ich euch da sicher nicht helfen. Sonst geht doch einfach mal den Thread zusammen durch und sucht den Punkt, wo ihr die Pronomen nicht mehr auflösen könnt. Das wäre dann schon fast so eine Art Selbsthilfegruppe. Al Fine schrieb: > Steht alles oben. Lesen, denken, verstehen. Wenn ihr schlicht zu dämlich > seid, einen deutschen Text zu lesen, kann ich euch da sicher nicht > helfen. > > Sonst geht doch einfach mal den Thread zusammen durch und sucht den > Punkt, wo ihr die Pronomen nicht mehr auflösen könnt. Das wäre dann > schon fast so eine Art Selbsthilfegruppe. Wunderbar: endlich wird der Thread hier so, wie wir es gewohnt sind in dieser Gruppe ;-) Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|