copy constructor und nicht-konstanter getter?



  • Hallo Leute,

    ich habe wieder ein Anliegen. Folgenes Beispiel:

    class MyClass
    {
    public:
    	MyClass():x(4) {}
    	~MyClass() {}
    
    	MyClass(const MyClass& other) {x = other.getVal();}
    
    	int getVal() const {return x;}
    
    private:
    
    	int x;
    
    };
    

    Die Variable x kann ich im Kopierkonstruktor nur kopieren, wenn ich den getter auf const setze. Soweit so gut. Aber was müsste ich tun, wenn ein getter per call-by-reference aufgerufen wird? Beispiel:

    int getBuf(unsigned char &buf) 
    {
       // ...kopiere irgendwelche Daten in 'buf' oder ähnliches... 
       return bytesCopied; // z.B. Anzahl der kopierten Bytes als Zusatzinfo
    }
    

    Diese Funktion kopiert Daten in einen angegebenen Puffer und gibt über den Rückgabewert die Anzahl der kopierten Bytes zurück. Diese Funktion ist nur ein Beispiel und könnte auch was ganz anderes sein. Problem ist zumindest, dass ich diesen getter nicht im Kopierkonstruktor verwenden kann. Ich kann den getter natürlich nicht auf const setzen und meine einzige Möglichkeit wäre hier, den Kopierkonstruktor ohne const aufzurufen. also so:

    MyClass(MyClass& other)
    

    ...ich denke das ist nicht so toll. Gibt es eine Möglichkeit 'getBuf()' im Kopierkonstruktor (MyClass(const MyClass& other)) aufzurufen?

    viele Grüße,
    Martin



  • SBond schrieb:

    int getBuf(unsigned char &buf) 
    {
       // ...kopiere irgendwelche Daten in 'buf' oder ähnliches... 
       return bytesCopied; // z.B. Anzahl der kopierten Bytes als Zusatzinfo
    }
    

    [...]Ich kann den getter natürlich nicht auf const setzen[...]

    Wieso?



  • Hallo SBond,

    private/protected/public gilt nur für andere Klassen bzw. Aufrufer und nicht für die eigene. (Mir fällt gerade keine bessere Formulierung ein ...)

    Warum also nicht direkt auf die Member-Variablen zugreifen?

    class MyClass
    {
    public:
        MyClass():x(4) {}
        MyClass(const MyClass& other):x(other.x) {}
        ~MyClass() {}
    
        int getVal() const {return x;} 
    private: 
        int x; 
    };
    

    Viele Grüße,



  • Danke für die Antworten 🙂

    @Caligulaminus: Wenn ich die Funktion auf const setze, dann kann ich auf den Parameter 'buf' nicht mehr schreibend zugreifen. Der Compiler schmeißt dann einen Fehler.

    Genauer gesagt handelt es sich um diese Funktion:

    int NtsClientAssocData::getNonceBuffer(unsigned char &destination, int num)
    {
    	// function tracker for debugging
    	SCOPE_LOGGER;
    
    	// check and return values
    	if (num == 0)
    	{
    	    throw Asn1Err (Asn1Err::INVALID_PARAMETER, THIS_LINE);
    	}
    
    	getOctetStringBuffer(destination, mp_clientAssocData->nonce, num);
    	return num;
    }
    

    Es ist ein Ausschnitt aus meinem Programm an dem ich gerade arbeite. Ich habe in meiner Klasse (NtsClientAssocData) nur eine member Variable (mp_clientAssocData). Diese Variable ist eine komplexe Struktur, in der auch dynamischer Speicher hängt. Soweit ich weiß, kann man solche Strukturen nicht 1:1 kopieren, sondern muss es wegen dem verwenderen dynamischen Speicher manuell machen. Da die Struktur zu viele (dynamische) Elemente beinhaltet, wäre ein manuelles kopieren der Elemente zu aufwändig. Daher kommen im Kopierkonstruktor getter und setter zum Einsatz, welche die entsprechenden Bereiche kopieren. Nur ist das Problem, dass ich 'getNonceBuffer(...)' nur aufrufen kann, wenn sich im Kopierkonstruktor kein 'const' befindet. Sowas: 'getNonceBuffer(...) const' geht nicht, da der enthaltene Methodenaufruf 'getOctetStringBuffer()' schreibend auf den Parameter 'destination' zugreift.

    Folgender kommt dann nämlich:

    error: passing ‘const NtsClientAssocData’ as ‘this’ argument of ‘int Asn1Wrapper::getOctetStringBuffer(unsigned char&, const OCTET_STRING_t&, int)’ discards qualifiers [-fpermissive]
    

    ...kann ich da irgendetwas machen?

    Achja: nicht wundern, dass der Parameter 'num' auch als Rückgabewert gesendet wird. Die Funktion ist noch nicht ganz fertig.

    viele Grüße,
    SBond



  • Hallo SBond,

    bist Du Dir sicher, dass Du ein Objekt was ein Buffer hält kopierbar werden soll?
    Ich öffne schließlich auch kein Dateistream und kopiere mir diesen (abgesehen davon funktioniert das sehr whrsch. nicht).

    Zwei Anmerkungen:
    * Die Member-Variable könnte auch als "mutable" gekennzeichnet werden, dann kannst Du diese auch in Const-Methoden ändern.

    * Warum nicht der Copy-Constructor von deiner komplexen Struktur aufrufen?

    struct Complex {
     int a;
     int b;
    };
    
    class MyClass {
    public:
      MyClass(const MyClass& other)
       : m_d( new Complex( *other.m_d ) ) {}
      // ...
    };
    

    Cheerio



  • jb schrieb:

    bist Du Dir sicher, dass Du ein Objekt was ein Buffer hält kopierbar werden soll?

    Ja 🙂

    Die dynamisch allozierten Bereiche sind sehr klein. Alle zusammen addiert sind eventuell 500 Byte groß. Das bloße kopieren der enthaltenen Pointer ist problematisch.

    Die Struktur wächst quasi mit ihren Inhalten. Sie hat mehrere Ebenen, die teilweise auch arrays von Strukturen enthalten. Die Struktur wurde mit einem ASN1-Compiler generiert und ist in C gehalten. Außerdem gibt es noch in C geschriebene Hilfsfunktionen (z.B. um die Struktur zu kodieren). Mit C++ habe ich quasi einen wrapper gebaut um Schnittstellen zu vereinfachen.

    jb schrieb:

    Die Member-Variable könnte auch als "mutable" gekennzeichnet werden, dann kannst Du diese auch in Const-Methoden ändern.

    Danke für den Tipp 🙂 Muss mich dahingehend erst belesen, da ich noch nicht viel damit anfangen kann.

    jb schrieb:

    Warum nicht der Copy-Constructor von deiner komplexen Struktur aufrufen?

    ...bin mir nicht sicher was du damit meinst 😕



  • destination ist nicht das Problem, da es kein Member deiner Klasse ist.
    Die Fehlermeldung sagt es ja auch: getOctetStringBuffer() ist nicht const .



  • oh nein.....

    du hast recht. Ja einige Funktionsebenen tiefer hat ein 'const' gefehlt. Vielen Dank 🙂

    ...habe schon ein schlechtes Gewissen hier zu schreiben. Ich kann noch nichtmal eine Fehlermeldung richtig lesen 😞 .

    Zumindest geht es jetzt. Vielen Dank und noch schöne Feiertage. 😃



  • jb schrieb:

    Hallo SBond,

    bist Du Dir sicher, dass Du ein Objekt was ein Buffer hält kopierbar werden soll?
    Ich öffne schließlich auch kein Dateistream und kopiere mir diesen (abgesehen davon funktioniert das sehr whrsch. nicht).

    Zwei Anmerkungen:
    * Die Member-Variable könnte auch als "mutable" gekennzeichnet werden, dann kannst Du diese auch in Const-Methoden ändern.

    * Warum nicht der Copy-Constructor von deiner komplexen Struktur aufrufen?

    struct Complex {
     int a;
     int b;
    };
    
    class MyClass {
    public:
      MyClass(const MyClass& other)
       : m_d( new Complex( *other.m_d ) ) {}
      // ...
    };
    

    Cheerio

    Ich werfe an der Stelle einfach die Rule-Of-Zero in den Raum.


Log in to reply