Warum können keine arrays übergeben werden, die als Funktion der Argumente?
Warum kann man nicht das übergeben von arrays als Funktionsargumente?
Habe ich gelesen, das C++ - Buch, das sagt: "du kannst nicht vorbei-arrays als Funktionsargumente', aber es wird nie erklärt, warum. Auch, wenn ich online nachgeschaut fand ich Kommentare wie " warum tust du das überhaupt?' Es ist nicht so, dass ich es tun würde, ich will nur wissen, warum du es nicht kannst.
- Bitte beachten Sie, den Körper von seinem text sagt, "mit Wert".
- Wahrscheinlich, weil das kopieren von ganzen arrays für den alleinigen Zweck der übergabe durch Wert als eine Funktion argument wird leicht dazu führen, stack-überläufe und/oder schrecklich langsam?
- silico: warum sind Sie Dann erlaubt zum erstellen von arrays als lokale Variablen, welche die gleiche automatische Lebensdauer?
- "denn das ist, wie C [und C++, weil seine Wurzeln] arbeitet" 🙂 natürlich mit C++, könnte std::vector oder was auch immer...
- Voigt: ich sehe nicht, wie das relevant ist für das Problem der übergabe von arrays per Wert. Was ich versuche zu bekommen, war, dass die übergabe von arrays durch Wert würde sicher beinhalten, das kopieren Ihrer Inhalte in den stack-frame, das ist eine Verschwendung von Zeit und Speicher, da die übergabe eines Zeigers auf das erste element gibt Ihnen die gleichen Möglichkeiten des Zugangs ist es aber so, dass Sie einfacher, schneller und weniger speicherintensiv.
- Sie wissen nicht, wie groß das array ist. Also, wie viel Speicherplatz für den array dauern wird, bis auf dem stack? Aber ähnlich wie die fn(int x, ...); Wenn Sie könnte, dann würde es zu const, da das hinzufügen von Elementen würde ärger geben.
- Aber es ist sehr anders als in C, um solche Entscheidungen zu treffen. Dürfen wir tun fast alles andere, was ist, wenn ich kopieren will mein array? Warum ist diese Regel gedämpft durch lediglich setzen das array in ein struct? Dein argument würde gelten, wie eine struct.
- silico: ich bin adressieren Sie Ihren Kommentar zu stack overflow. Arrays als lokale Variablen stack-überlauf verursachen genauso schnell, wie array-Parameter. Nur übergeben Sie einen Zeiger (oder eine Referenz) hat sehr unterschiedliche Semantik, sowohl in Bezug auf aliasing und änderungen überleben der Aufruf der Funktion.
- Nicht mehr ist es nicht.
- Voigt: ich sehe, was du jetzt meinst. Ich stehe korrigiert.
- Ich vergaß über arrays in
struct
s. Ich tadeln es auf mein Vertrauen auf die C++ - Container. 🙂
Du musst angemeldet sein, um einen Kommentar abzugeben.
Können Sie:
In technischer Hinsicht, die Art der Argumentation
foo
ist "Verweis auf ein array von 5const
int
s"; mit Referenzen, dann können wir auch die tatsächlichen Objekt um (Haftungsausschluss: Terminologie variiert je nach Abstraktionsebene).Was Sie nicht tun können, ist pass von Wert, weil aus historischen Gründen sind wir nicht kopieren arrays. Stattdessen, versuchen, übergeben Sie ein array als Wert in eine Funktion (oder, übergeben kopieren eines Arrays) führt seinen Namen Zerfall in einen Zeiger. (einige Ressourcen, die verstehen das falsch!)
Array-Namen zerfallen zu Zeigern für pass-by-value
Bedeutet dies:
Gibt es auch die äusserst irreführend sind "syntaktischer Zucker", die sieht wie können Sie übergeben Sie ein array von beliebiger Länge durch Wert:
Aber, tatsächlich, du bist immer noch nur auf der Durchreise zu einem Zeiger (auf das erste element
ar
).foo
ist die gleiche wie oben!Während wir gerade dabei sind, die folgende Funktion auch nicht wirklich die Handschrift, so scheint es. Schauen Sie, was passiert, wenn wir versuchen, diese Funktion aufrufen, ohne es zu definieren:
So
foo
nimmtint*
in der Tat nichtint[5]
!(Live-demo.)
Aber man kann-um es!
Können Sie hack, um dieses durch die Verpackung des Arrays in einer
struct
oderclass
, da die Standard-copy-operator wird copy-array:Dies ist etwas verwirrend Verhalten.
Oder, besser, eine generische pass-by-reference-Ansatz
In C++ mit template-Magie, die wir machen können, eine Funktion sowohl wieder verwendbar und in der Lage zu erhalten ein array:
Aber wir können noch nicht übergeben Sie einen Wert. Etwas zu erinnern.
Die Zukunft...
Und seit C++11 ist knapp über dem Horizont, und C++0x support kommen zusammen schön in den mainstream-toolchains, können Sie die schöne
std::array
geerbt, die von Boost! Ich lasse die Erforschung, die als übung für den Leser.So sehe ich die Antworten, die erklären, "Warum macht das nicht der compiler erlauben Sie mir, dies zu tun?" Eher als "das, Was verursacht die standard legen Sie dieses Verhalten?" Die Antwort liegt in der Geschichte von C. Diese ist entnommen aus "Die Entwicklung der C-Sprache" (Quelle) von Dennis Ritchie.
In den proto-Sprachen C, Speicher wurde unterteilt in "Zellen", die jeweils ein Wort. Diese könnten aufgelöst werden, über die eventuelle unäre
*
Betreiber -- ja, dies waren im wesentlichen typeless Sprachen wie einige der heutigen Spielzeug-Sprachen wie Brainf_ck. Syntaktischer Zucker ermöglichte die vorgeben, ein Zeiger wurde ein array:Dann die automatische Zuordnung Hinzugefügt:
Irgendwann der
auto
storage-Bezeichner Verhalten wurde Standard-Sie können auch Fragen, was der Punkt derauto
Stichwort war eh, das ist es. Zeiger und arrays gelassen wurden, um das Verhalten in etwas skurrile Art als Ergebnis dieser inkrementellen änderungen. Vielleicht sind die Typen Verhalten würde sich mehr ähnlich, wenn die Sprache, die entworfen wurden, aus einer Vogelperspektive. So wie es da steht, dies ist nur eine weitere C /C++ gotcha.*
Betreiber oder Zugriff auf array-Elemente mitx[i]
syntax, das ist die Kurzform für*(x+i)
. Beim übergeben einer Variablen an eine Funktion übergeben Sie den Wert mit keine Tiefe Kopie, so dass Sie nicht passieren können, den Inhalt eines Arrays. Es ist bequem zu reservieren, stack-Speicher, daher derauto
Schlüsselwort. Doch an diesem Punkt ist es nur initialisiert eine lokale, mit einem Zeiger auf den stack. Es ist immer noch ein Zeiger und der Speicher-Punkte, um nicht kopiert werden.Arrays sind in ein Gefühl zweiter Klasse Typen, etwas, was C++ geerbt von C.
Zitieren 6.3.2.1p3 in der C99-standard:
Gleichen Absatz in der C11-standard ist im wesentlichen der gleiche, mit dem Zusatz von der neuen
_Alignof
Betreiber. (Beide links sind Entwürfe, die sehr nah an den offiziellen standards. (UPDATE: Das war tatsächlich ein Fehler in der N1570 Entwurf, korrigiert, veröffentlicht in der C11-standard._Alignof
können, werden nicht angewandt auf einen Ausdruck, nur eine in Klammern eingeschlossene Typ-Namen, also C11 hat nur die gleichen 3 Ausnahmen, die C99 und C90 hat. (Aber ich schweife ab.)))Habe ich nicht die entsprechenden C++ citation praktisch, aber ich glaube, es ist ziemlich ähnlich.
Also, wenn
arr
ist ein array-Objekt, und rufen Sie eine Funktionfunc(arr)
, dannfunc
erhalten einen Zeiger auf das erste elementarr
.Bislang ist dies mehr oder weniger "funktioniert es so, weil es ist definiert, der Weg", aber es gibt historische und technische Gründe.
Erlaubt array-Parameter würde nicht zulassen, dass für viel Flexibilität (ohne weitere änderungen an der Sprache), da zum Beispiel
char[5]
undchar[6]
sind unterschiedliche Typen. Auch die übergabe von arrays per Referenz nicht helfen (es sei denn, es gibt einige C++ - Funktion fehlt mir, immer eine Möglichkeit). Übergabe von Zeigern gibt Ihnen enorme Flexibilität (vielleicht zu viel!). Der pointer auf das erste element eines Arrays beliebiger Größe-aber du musst Rollen Sie Ihre eigenen Mechanismus zu sagen, die Funktion, wie groß das array ist.Entwerfen einer Sprache, so dass arrays von verschiedenen Längen sind einigermaßen kompatibel, während immer noch ausgeprägt ist tatsächlich ziemlich verzwickt. In Ada zum Beispiel, die äquivalente
char[5]
undchar[6]
sind die gleichen Typ, aber unterschiedliche Subtypen. Dynamischer Sprachen stellen Sie die Länge ein Teil eines array-Objekts den Wert, nicht von seinem Typ ab. C noch ziemlich viel muddles zusammen mit expliziten Zeigern und Längen, oder Zeiger und terminatoren. C++ geerbt alle, die Gepäck von C. Es meist Stakte auf die gesamte array-Sache eingeführt und Vektoren, also es war nicht so viel brauchen, um arrays erste-Klasse-Typen.TL;DR: Das ist C++, sollten Sie mit Hilfe von Vektoren sowieso! (Gut, manchmal.)
std::array
. 🙂Arrays werden nicht per value übergeben, da arrays sind im wesentlichen kontinuierliche Blöcke von memmory. Wenn Sie ein array erhalten Sie wollte durch Wert übergeben, Sie könnte es erklären, innerhalb einer Struktur und dann auf Sie durch die Struktur.
Dieser selbst hat Auswirkungen auf die Leistung, da es bedeutet, Sie zu sperren, bis Sie mehr Speicherplatz auf dem stack. Wird ein Zeiger übergeben wird schneller, weil die Hüllkurve der Daten kopiert werden, auf dem stack ist weit weniger.
int a[10];
, der namea
hat der Typint[10]
, und ist eine zusammenhängende Sammlung von zehn Ganzzahlen.Ich glaube, der Grund, warum C++ war dies, wenn es erstellt wurde, dass es hätte zu viele Ressourcen zu senden, die das gesamte array anstatt die Adresse im Speicher. Das sind lediglich meine Gedanken zu dem Thema und eine Annahme.
Es da einen technischen Grund. Argumente werden auf den stack gelegt; ein array kann eine enorme Größe, Megabyte und mehr. Das kopieren von Daten auf den Stapel bei jedem Aufruf wird nicht nur langsamer, aber Sie erschöpfen die Stapel ziemlich schnell.
Können Sie überwinden diese Einschränkung, indem Sie ein array in ein struct (oder mit Boost::Array):
Versuchen, um verschachtelte Aufrufe der Funktion und sehen, wie viele stack-overflows, die Sie erhalten!