Initialisierung einer const-variablen mit im Konstruktor berechneten Wert



  • Hallo,

    ich habe folgendes Problem:

    Ich habe mir eine Klasse für einen Octree gebaut und möchte die totale Anzahl an Nodes als const speichern (Beispiel stark vereinfacht):

    // Octree.h
    class Octree {
    
    public: 
        Octree(const unsigned int level);
    
    private:
        const unsigned int levels;
        const unsigned int degree;
        const unsigned int total_nodes;
    };
    
    // Octree.cpp
    #include "Octree.h"
    
    Octree::Octree(const unsigned int level)
            : levels(level), degree(8), total_nodes( ??? )
    {
        unsigned int total_nodes = 1 // root_node
        unsigned int node_counter = 1;
    
        for(unsigned int level = 1; level < levels; level++) {
            node_counter *= degree; //degree ^ level = nodes per level
            total_nodes += node_counter
        }
    
        // zuweisung, ich hatte total_nodes bislang nicht const...
        this->total_nodes = total_nodes;
    }
    

    Das Problem was ich habe ist jetzt, wie kann ich total_nodes als const deklarieren, aber einen Wert zuweisen den ich erst nach einigen Berechnungen im Konstruktor kenne? Ich meine mich zu erinnern, dass das zumindest in Java problemlos ging... Gibts für C++ eine saubere Lösung?

    Vielen Dank!

    Gruß


  • Mod

    chmbw schrieb:

    Gibts für C++ eine saubere Lösung?

    Ja. Allerdings sind nicht-statische const-Member in 99.9% aller Fälle Unfug.



  • Danke für deine Antwort, aber könntest du das bitte ein wenig weiter ausführen?



  • chmbw schrieb:

    Danke für deine Antwort, aber könntest du das bitte ein wenig weiter ausführen?

    Mach das const weg.



  • Der Modifizierer const bedeutet, dass es sich um eine Konstante handelt, die im
    Programm nicht veränderbar sein soll! Also z.B. pi = 3.15927 oder so.

    Was willst du? 😕 Mit const kommst du hier nicht rein! 😞



  • Du könntest auch einfach den Code in eine Funktion auslagern und dann so initialisieren:

    Octree::Octree(const unsigned int level)
            : levels(level), degree(8), total_nodes( CalcTotalNodes(level) )
    {
    }
    

    Für 'degree' würde ich dir aber auch

    static const unsigned int degree = 8;
    

    empfehlen (gilt für C++11 - ansonsten mußt du separat Deklaration und Definition auf Header und Source aufteilen), da es ja keine Konstante ist, welche sich je Objekt unterscheidet.


  • Mod

    berniebutt schrieb:

    Der Modifizierer const bedeutet, dass es sich um eine Konstante handelt, die im
    Programm nicht veränderbar sein soll! Also z.B. pi = 3.15927 oder so.

    Nicht unbedingt. Es gibt const auch in seiner Funktion, dass man eine Variable nicht ändern kann. Das machst du ganz unbewusst bei Referenzen auf const, aber geht prinzipiell auch auf oberster Ebene, so wie hier gezeigt. Bloß ist es da nur sehr selten sinnvoll. Beispiele dafür müsste man regelrecht konstruieren.



  • Ich nutze gelegentlich bspw. konstante Zeiger.
    T* const ptr;
    Auch als Klassenmember. Wenn einfach eine Referenz auf ein Objekt benötigt wird, die schon rein semantisch gar nicht verändert werden darf.

    Was ist so falsch daran? Das gehört sicherlich nicht zu den 0,01%.


  • Mod

    Sone schrieb:

    Was ist so falsch daran? Das gehört sicherlich nicht zu den 0,01%.

    Nichts. Ich habe auch nirgendwo Zahlen genannt. Es ist eben bloß nicht sehr häufig. Ich glaube die Anzahl der Fälle, in denen ich so etwas benutzt habe und (voraussichtlich noch nutzen werde), ist über mein gesamtes Leben < 20.



  • camper schrieb:

    chmbw schrieb:

    Gibts für C++ eine saubere Lösung?

    Ja. Allerdings sind nicht-statische const-Member in 99.9% aller Fälle Unfug.

    Ich hab' haufenweise nicht-statische const-Member in meinem Code.
    Wenn da const steht kann ich mir sicher sein dass das Ding nirgends verändert wird. Finde ich super-praktisch wenn es darum geht Code zu verstehen bzw. sich einen Überblick zu verschaffen. Quasi als besserer Ersatz für ein " ... // invariant " Kommentar. Besser weil der Compiler mir nen Fehler um die Ohren wirft falls es gelogen ist. (Natürlich nur unter der Annahme dass man nicht absichtlich versucht zu lügen, also nicht const_cast o.ä. verwendet um die Dinger zu ändern. Darauf kann ich mich bei unserem Code aber gottseidank verlassen.)

    Macht natürlich nur bei Klassen Sinn die non-copyable und non-movable sind. Wovon in der Anwendungsentwicklung, zumindest wenn man so programmiert wie ich, reichlich viele entstehen.



  • SeppJ schrieb:

    Sone schrieb:

    Was ist so falsch daran? Das gehört sicherlich nicht zu den 0,01%.

    Nichts. Ich habe auch nirgendwo Zahlen genannt. Es ist eben bloß nicht sehr häufig. Ich glaube die Anzahl der Fälle, in denen ich so etwas benutzt habe und (voraussichtlich noch nutzen werde), ist über mein gesamtes Leben < 20.

    Man kann in C++ ganz ohne const programmieren. Dann braucht man const auch kaum, nämlich immer nur dann wenn man irgendeine Schnittstelle implementieren muss die const verwendet.
    Das heisst aber nicht das const sinnlos wäre, oder nur in extrem wenigen Fällen Sinn macht.

    Das selbe gilt mMn. für non-static const Member.

    Mit dem passenden "mindset" ergibt sich sehr oft die Möglichkeit das sinnvoll einzusetzen. Wenn man es aber bereits mental unter "braucht man fast nie" abgelegt hat, dann wird man kaum sinnvolle Anwendungmöglichkeit sehen.



  • Erstmal herzlichen Dank für eure zahlreichen Antworten!
    Die überlegung "const" bei total_nodes zu verwenden kam daher, dass der Wert halt nur ein einziges mal für die entsprechende Klasseninstanz bestimmt wird, danach aber gar nicht mehr geändert werden darf.

    Th69 schrieb:

    Du könntest auch einfach den Code in eine Funktion auslagern und dann so initialisieren:

    Octree::Octree(const unsigned int level)
            : levels(level), degree(8), total_nodes( CalcTotalNodes(level) )
    {
    }
    

    Für 'degree' würde ich dir aber auch

    static const unsigned int degree = 8;
    

    empfehlen (gilt für C++11 - ansonsten mußt du separat Deklaration und Definition auf Header und Source aufteilen), da es ja keine Konstante ist, welche sich je Objekt unterscheidet.

    Herzlichen Dank!

    SeppJ schrieb:

    berniebutt schrieb:

    Der Modifizierer const bedeutet, dass es sich um eine Konstante handelt, die im
    Programm nicht veränderbar sein soll! Also z.B. pi = 3.15927 oder so.

    Nicht unbedingt. Es gibt const auch in seiner Funktion, dass man eine Variable nicht ändern kann. Das machst du ganz unbewusst bei Referenzen auf const, aber geht prinzipiell auch auf oberster Ebene, so wie hier gezeigt. Bloß ist es da nur sehr selten sinnvoll. Beispiele dafür müsste man regelrecht konstruieren.

    Das mit den Referenzen ist keine Frage, das mache ich ebenfalls gern. Aber wieso meinst du ist es auf "oberster" Ebene (ich denke du meinst z.B. für einfache Variablen wie "levels" oder "total_nodes") sehr selten sinnvoll? Meine Intention ist nämlich die, die hustbaer beschrieben hat:

    hustbaer schrieb:

    Wenn da const steht kann ich mir sicher sein dass das Ding nirgends verändert wird. Finde ich super-praktisch wenn es darum geht Code zu verstehen bzw. sich einen Überblick zu verschaffen. Quasi als besserer Ersatz für ein " ... // invariant " Kommentar. Besser weil der Compiler mir nen Fehler um die Ohren wirft falls es gelogen ist.


  • Mod

    chmbw schrieb:

    Das mit den Referenzen ist keine Frage, das mache ich ebenfalls gern. Aber wieso meinst du ist es auf "oberster" Ebene (ich denke du meinst z.B. für einfache Variablen wie "levels" oder "total_nodes") sehr selten sinnvoll? Meine Intention ist nämlich die, die hustbaer beschrieben hat:

    hustbaer schrieb:

    Wenn da const steht kann ich mir sicher sein dass das Ding nirgends verändert wird. Finde ich super-praktisch wenn es darum geht Code zu verstehen bzw. sich einen Überblick zu verschaffen. Quasi als besserer Ersatz für ein " ... // invariant " Kommentar. Besser weil der Compiler mir nen Fehler um die Ohren wirft falls es gelogen ist.

    Da sind sich hustbaer und ich eben einfach uneinig. Kommt vor. Ist sicherlich keine der Stilfragen, bei denen ich um ein richtig oder falsch kämpfen würde. Ich find's halt unnötig, weil es weder technisch noch syntaktisch einen Unterschied macht (außer vielleicht dein spezieller Fall hier); hustbaer nicht, weil es ihm hilft, den Code besser zu verstehen.



  • herzlichen Dank 🙂 und wieder was gelernt 😉



  • SeppJ schrieb:

    hustbaer nicht, weil es ihm hilft, den Code besser zu verstehen.

    Ich mag auch alle Sachen die mir helfen eigene Fehler durch "nicht nachgedacht" zu vermeiden.
    Und const finde ich da ziemlich kuhl, ziemlich egal worauf es sich bezieht.

    Das einzige was mir jetzt einfällt wo ich es nie mache, ist top-level const bei Parametern. void f(int const x); // <- wirklich total sinnfrei

    Aber ja, bei non-static Membern kann man sich durchaus darauf einigen unterschiedlicher Meinung zu sein. Gibt wichtigeres 🙂



  • Nur so am Rande: Ich verwende const bei nicht-statischen Elementen so gut wie nie. Das macht bei fast allen Klassen, die ich schreibe, keinen Sinn. Bei einem Octree würde mir das auch nicht in den Sinn kommen.



  • krümelkacker schrieb:

    Nur so am Rande: Ich verwende const bei nicht-statischen Elementen so gut wie nie. Das macht bei fast allen Klassen, die ich schreibe, keinen Sinn. Bei einem Octree würde mir das auch nicht in den Sinn kommen.

    Sehe ich aehnlich. Ueberall wo ich es mal hingesetzt habe, musste ich es nachtraeglich wieder entfernen.

    non-copyable und non-movable

    Darunter fallen beispielsweise Adapter- oder Wrapperklassen, jedoch biete der Adapter meist Funktionalitaet an, die das Objekt veraendern. Ich frage mich wirklich, was das fuer Klassen sind, die const-Member haben.


  • Mod

    knivil schrieb:

    Ich frage mich wirklich, was das fuer Klassen sind, die const-Member haben.

    Proxy-Klassen (wobei man durch das const dort auch nichts gewinnt, es stört nur nicht).


Anmelden zum Antworten