arrays bei methoden call erstellen



  • hallo,

    ich habe vor kurzem mit c++ angefangen und habe eine frage. in c# ist
    es möglich ein array beim aufruf einer methode zu deklarieren. etwa
    so :

    float foo(int[] x){}
    ...
    foo (new int[]{0,1,2,3});
    

    ist das auch in c++ möglich ? verwende ich die gleiche syntax, so bekomme ich
    compiler fehler ab der definition des inhalts des arrays. ich verwende die
    typen real und long im rahmen einer sdk. der code sollte os-unabhängig sein,
    also iso c++.

    vielen dank für eure antwort im voraus.



  • dir fehlt da die schließende Klammer
    C++ ist KEIN C#. Zu jedem new gehört auch ein delete (ich nehme stark an, dass in der foo Funktion kein delete gemacht wird)

    greetz KN4CK3R



  • KN4CK3R schrieb:

    dir fehlt da die schließende Klammer
    C++ ist KEIN C#. Zu jedem new gehört auch ein delete (ich nehme stark an, dass in der foo Funktion kein delete gemacht wird)

    greetz KN4CK3R

    danke den tippfehler mit der klammer habe ich behoben. das c++ kein c# ist, ist
    mir schon klar, deshalb frag ich hier ja so blöd 🙂 ich würde gern wissen ob es
    eine entsprechung gibt.



  • float foo(int *x, size_t length);
    

    So sieht das C(++)-Äquivalent aus. Die Länge muss zusätzlich übergeben werden, weil der Zeiger diese Information nicht beinhaltet.

    Wenn die Anzahl der Elemente dynamisch ist:

    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    //...
    foo(&v[0], v.size());
    

    Wenn die Anzahl bekannt ist, reicht array :

    std::array<int, 2> a = {{1, 2}};
    foo(a.data(), a.size());
    


  • In der Form ist das nicht möglich. Es wäre auch ziemlich heikles Design, weil die Methode wissen müsste, dass sie den Heap-Speicher nachher wieder aufräumen muss - in C++ gibt es keinen Garbage-Collector.

    Was geht, ist

    int arr[] = { 0, 1, 2, 3 }; // Merke: Array auf dem Stack
    
    foo(arr, 4); // Die Länge wird dann üblicherweise mitgegeben.
    

    Für Arrays dynamischer Länge gibt es std::vector (der kennt dann auch seine Länge selbst), und wer Bequemlichkeit beim Initialisieren sucht, für den gibt es Boost.Assign.

    Im neuen Standard (C++11), der allerdings noch nicht überall implementiert ist, gibt es darüber hinaus einige Neuerungen, die Schreibweisen erlauben, wie du sie suchst. Beispielsweise geht da

    void foo(std::vector<int> const &v) { ... }
    
    ...
    
    foo({ 0, 1, 2, 3 });
    

    Ich könnte dir auf Anhieb allerdings nicht sagen, durch welche Compiler du das schon gequetscht kriegst.



  • TyRoXx schrieb:

    float foo(int *x, size_t length);
    

    holla, das geht hier aber fix. diese konstruktion mit dem pointer verstehe ich
    schlicht nicht. ich kenne zwar referencing und dereferencing, aber ich verstehe
    nicht, wie mir das in diesem fall hilft, da der inhalt des parameters auch mit
    einem pointer noch definiert werden muss. könnte ich vielleicht bitte diedummy
    erklärung bekommen bitte 😃

    seldon schrieb:

    In der Form ist das nicht möglich...

    das hatte ich befürchtet, da ich mit google zu dem thema nichts gefunden habe.
    als ide/compiler verwende ich VS 2005, da muss man noch kurbeln zum kompilieren 😉



  • Teiresias schrieb:

    als ide/compiler verwende ich VS 2005, da muss man noch kurbeln zum kompilieren 😉

    Darf ich mal fragen ob der dir irgendwie vorgegeben wird, oder warum du keinen neueren nimmst?

    Teiresias schrieb:

    da der inhalt des parameters auch
    mit einem pointer noch definiert werden muss

    schau dir das erste Beispiel von seldon an, du musst hier keinen Zeiger definieren. Bei der übergabe eines Arrays erhältst du im wesentlichen den Zeiger auf das erste Element (Auch bekommst du keine Größeninformation mitgeliefert, daher ein weiterer Parameter).



  • asc schrieb:

    Darf ich mal fragen ob der dir irgendwie vorgegeben wird, oder warum du keinen neueren nimmst?

    ist halt die empfohlene IDE für das aktuelle c4d sdk 2012. und da wohl schon das
    kompilieren der api projekte in anderen IDEs in übeles gefrickelt ausartet habe
    ich mich für vs 2005 entschieden.

    asc schrieb:

    schau dir das erste Beispiel von seldon an, du musst hier keinen Zeiger definieren.

    so mache ich es natürlich momentan, habe bis jetzt den umstand immer ignoriert,
    aber es würde natürlich eniges an zeilen sparen wenn man sich die getrennte
    deklaration sparen könnte.

    edit :

    hier ein beispiel des code

    LONG value[] = {PLIGHT_LIGHT_TYPE_DISC};
    UnHideDescription(PLIGHT_DISC_GRP, DTYPE_GROUP, data->GetLong(PLIGHT_LIGHT_TYPE) , value, FALSE , singleid, description);
    
    ...
    
    void Opolylight::UnHideDescription(LONG targetid, LONG dtype, LONG checkvalue, LONG value[], Bool isequal, const DescID *singleid, Description *description)
    {
    	BaseContainer *bc;
    	DescID cid;
    
        cid = DescLevel(targetid, dtype, 0);
    
    	if(!singleid || cid.IsPartOf(*singleid, NULL))
    	{
    		bc = description->GetParameterI(cid, NULL);
    		if (isequal)
    		{
    			for (int i = 0; i <(sizeof(value) / sizeof(LONG));i++)
    			{
    				if (checkvalue == value[i])
    					bc->SetBool(DESC_HIDE, TRUE);
    				else 
    					bc->SetBool(DESC_HIDE, FALSE);
    			}
    		}
    		else
    		{
    			for (int i = 0; i < (sizeof(value) / sizeof(LONG));i++)
    			{
    				if (checkvalue != value[i])
    					bc->SetBool(DESC_HIDE, TRUE);
    				else 
    					bc->SetBool(DESC_HIDE, FALSE);
    			}
    		}
        }
    }
    


  • Teiresias schrieb:

    void Opolylight::UnHideDescription(LONG targetid, LONG dtype, LONG checkvalue, LONG value[], Bool isequal, const DescID *singleid, Description *description)
    {
      ...
    			for (int i = 0; i <(sizeof(value) / sizeof(LONG));i++)
      ...
    }
    

    Ganz schlechte Idee. value ist in diesem Kontext ein einfacher Zeiger; sizeof(value) / sizeof(LONG) ist das selbe wie sizeof(LONG*) / sizeof(LONG).

    Statt der sizeof/sizeof-Konstruktion ist Folgendes besser:

    template<typename T, std::size_t N>
    std::size_t array_size(T(&)[N]) { return N; }
    

    ...damit kann man diesen Fehler nicht mehr machen (der Compiler meckert, wenn man da einen Zeiger reinwirft). Du wirst, wenn du es über einfache Arrays machen willst, die Länge des Arrays mit übergeben müssen.



  • TyRoXx schrieb:

    float foo(int *x, size_t length);
    

    So sieht das C(++)-Äquivalent aus.

    Ähm. Nein. int[] in C# ist eine Klasse, kein blankes Array, also in etwa ein std::vector. Dementsprechend wäre das für C++ viel "natürlichere" Äquivalent dann auch

    float foo(std::vector<int>& arr);
    

    Wenn du gleich die von seldon gezeigte Syntax haben möchtest, ohne an den Werten etwas zu verändern (readonly), dann wäre eine Überladung sinnvoll, um eine unnötige vector-Konstruktion mit Speicheranforderung etc. zu vermeiden:

    float foo(std::initializer_list<int> il);
    


  • pumuckl schrieb:

    TyRoXx schrieb:

    float foo(int *x, size_t length);
    

    So sieht das C(++)-Äquivalent aus.

    Ähm. Nein. int[] in C# ist eine Klasse, kein blankes Array, also in etwa ein std::vector.

    Das liegt an der Natur von C#, da ist alles eine Klasse oder eine Struktur.
    Was soll diese Benennung mit der Semantik zu tun haben?
    Semantisch entspricht das C#-Array einem Zeiger mit Längeninformation. Nichts vector .

    pumuckl schrieb:

    Dementsprechend wäre das für C++ viel "natürlichere" Äquivalent dann auch

    float foo(std::vector<int>& arr);
    

    Das ""natürliche"" Äquivalent wäre für C++ wohl

    template <class Iterator>
    float foo(Iterator begin, Iterator end);
    


  • ich quote jetzt mal nicht alles, ich halte nur folgendes fest :

    1. die ursprüngliche fragestellung ist nur mit c++ 11 oder libs wie Boost.Dingsbums möglich ?

    2. ich stolpere mit meinem halbgaren c# wissen, mehr blind als wissend
    durch meinen eigenen c++ code, aber in den sdk beispielen verwendet maxon
    nie den standard namespace , deshalb habe ich mich bis jetzt auch daran
    gehalten und std ignoriert.

    3. das sizeof extrem frickelig ist, ist selbst mir klar :). habe es als
    schnellen ersatz für mein sonst so geliebtes for each verwendet. die c4d
    api bietet zwei klassen für dynamische arrays, ich denke ich sollte diese
    verwenden. aber da die die arrays in dem fall immer nur readonly und auch
    befüllt sind funktionert es zumindest.

    vielen dank für eure hilfe nochmals.



  • TyRoXx schrieb:

    Das liegt an der Natur von C#, da ist alles eine Klasse oder eine Struktur.

    Ist mir völlig klar. Dein Ansatz, die C#-Klasse mit Zugriffsüberprüfung, "automatischer" Speicherverwaltung (GC) usw. in C++ durch einen dummen C-Pointer plus Längenangabe darzustellen hat aber zu dem Eindruck geführt, du hättest int[] in C# mit int[] in C(bzw. C++) gleichgesetzt.

    TyRoXx schrieb:

    Semantisch entspricht das C#-Array einem Zeiger mit Längeninformation. Nichts vector .

    Ein std::vector ist ein Zeiger mit Längeninformation (und automatischer Speicherfreigabe, und bei Bedarf Indexprüfung...). Der std::vector ist nicht weit vom C-Ansatz "Pointer plus Längenangabe" entfernt, was die Semantik des Funktionsaufrufs angeht, aber eben was den Umgang damit vor und nach dem Aufruf angeht.

    Das ""natürliche"" Äquivalent wäre für C++ wohl

    template <class Iterator>
    float foo(Iterator begin, Iterator end);
    

    Das wäre der C++03-Algorithmen-Ansatz und in C# wiederum auch mit Iteratoren machbar. Wenn du es ganz generisch haben möchtest, schreibst du

    template <class Container>
    float foo(Container& cont)
    {
      for (auto& elem : cont) { /* ... */ }
    }
    

    Teiresias schrieb:

    1. die ursprüngliche fragestellung ist nur mit c++ 2011 oder libs wie Boost.Dingsbums möglich ?

    Wenn du es so direkt und einfach lesbar haben möchtest, ja.

    2. ich stolpere mit meinem halbgaren c# wissen, mehr blind als wissend
    durch meinen eigenen c++ code, aber in den sdk beispielen verwendet maxon
    nie den standard namespace , deshalb habe ich mich bis jetzt auch daran
    gehalten und std ignoriert.

    Dass in irgendwelchen Codebeispielen keine Standardbibliothek benutzt wird, kann verschiedenes bedeuten:
    a) Das SDK um das es geht, benutzt für alle Sachen, die es als nötig erachtet eine eigene Biblitohek, die Dinge nachbildet, die es in der Standardbibliothek in ähnlicher Form auch gibt.
    b) Das SDK und die Code-Beispiele benutzen einen reichlich antiquitierten "C-mit-Klassen"-Stil, der nur geschätzte 0,02% der Möglichkeiten von C++ nutzt. Der erste Eindruck des Codebeispiels oben stützt leider Möglichkeit b).
    Wie auch immer, weder a) noch b) sind ein ausreichender Grund, warum du in deinem Code auf sämtliche Werkzeuge verzichten solltest, die C++ dir bietet.



  • Die Standardbibliothek zu ignorieren ist eine ziemlich schlechte Idee. Warum Maxon in seinen Codebeispielen eigenen Kram verwendet, solltest du womöglich mal erfragen; vermutlich sind das einfach Altlasten. Cinema4D gibt es ja schon seit den frühen Neunzigern, und C++ wurde erst 1998 standardisiert. Denkbar auch, dass die Leute, die den Kram ursprünglich entwickelt haben, eher eine C-Denkweise drauf hatten - was in C++ als guter Stil angesehen wird, hat sich seit der Standardisierung ja dramatisch verändert.



  • die c4d api hat eine eigene speicherverwaltung, ich glaube das ist der grund
    warum man sich nur innerhalb der maxon api bewegen soll. es gibt einen gc
    namens autoalloc. außerdem soll man sich auf die typen bool, real, long und
    was eben der c4d namespace hergibt beschränken. ausserdem ist c4d xl5 (1999)
    meines wissens nach ein kompletter neuentwurf gewesen. (die gute packung mit
    dem ollen chrom panther 😃 *schnief*)

    habe das auch nur erwähnt, um zu verdeutlichen, warum ich nicht näher auf die
    vorschläge eingehe, die den std namespace verwenden. mich persönlich ärgert es
    immer, wenn man versucht hilfestellung zu geben , aber die fragenden in der
    versenkung verschwinden oder nicht auf antworten reagieren.

    in diesem fall werde ich mich aber an maxon halten und std ignorien 🙂


Log in to reply