2013-07-24 8 views
6

Ich schaute durch die Interview Fragen zu einem Junior C++ Entwickler-Position. Die Frage ist (Zitat):Ändern konstantes Objekt

Ist der folgende Code korrekt?

struct Foo 
{ 
    int i; 
    void foo (void) const 
    { 
     Foo* pointer = const_cast<Foo*>(this); 
     pointer->i = 0; 
    } 
}; 

Ich würde antworten: erfolgreich

Der Code selbst 03 nach dem C++ gültig ist und C++ 11-Standards und kompilieren. Aber es kann ein undefiniertes Verhalten während der Zuweisung Zeiger-> i = 0; Wenn die Instanz der Klasse, für die foo() aufgerufen wird, als const deklariert wird.

Ich meine, dass der folgende Code wird erfolgreich kompilieren und zu undefiniertem Verhalten führen.

struct Foo 
{ 
    int i; 
    Foo (void) 
    { 

    } 
    void foo (void) const 
    { 
     Foo* pointer = const_cast<Foo*>(this); 
     pointer->i = 0; 
    } 
}; 

int main (void) 
{ 
    Foo foo1; 
    foo1.foo(); // Ok 

    const Foo foo2; 
    foo2.foo(); // UB 

    return 0; 
} 

Ist meine Antwort korrekt oder fehlt mir etwas? Vielen Dank.

+11

Ja, es ist korrekt. –

+3

"Korrekt" ist eher ein vages Wort. Es ist * wohlgeformt *, was bedeutet, dass es keine diagnostizierbaren Fehler gibt, aber (wie Sie sagen) zu undefiniertem Verhalten führen kann. –

+0

IMO von einem Design-POV ist es nicht "richtig" weil 'const Foo foo; foo.foo(); 'sollte nicht UB sein. Ein "veränderbares" Mitglied wäre besser. – StackedCrooked

Antwort

5

Ich würde zuerst fragen, was mit ihrer mehrdeutigen Definition von "richtig" gemeint ist. Sie müssen die Spezifikation des Programms und dessen beabsichtigtes Verhalten kennen.

Wie Sie gesagt haben, wenn sie nur fragen, ob es kompiliert, dann ist die Antwort "ja". Wenn sie jedoch feststellen, dass es korrekt ist, um sicher zu sein, können Sie die Fakten, die Sie in Ihrer Frage angeben, besprechen.

Wenn Sie auf diese Weise antworten, kann die Person, die interviewt, sehen, wie Sie analysieren, was Sie gefragt werden, anstatt direkt in die Beantwortung zu springen, was meiner Meinung nach eine gute Sache ist.

1

Dieser Code mag rechtlich korrekt sein, aber ich denke, das Ziel der Frage ist festzustellen, ob Sie das Konzept von const selbst verstanden haben. Weil Sie auf der semantischen Ebene eine Funktion haben, die einen impliziten const Objektzeiger nimmt, den es dann ändert, was mit ziemlicher Sicherheit ein Fehler ist.

Es gibt Fälle, in denen dies erwünscht ist (weil die Änderung ein Zwischenspeichern von Rückgabewerten oder eine ähnliche Operation ist, die den semantischen Wert des Objekts nicht ändert), Sie würden das Schlüsselwort mutable für die betreffende Variable verwenden .

+0

Vielen Dank. Dies ist eine nette Idee, in der Antwort zu erwähnen, dass das Erklären von "i" als "veränderbar" das erwähnte mögliche UB beheben wird. – Kolyunya

+0

Das Entfernen von * constness * ist ein Zeichen für einen Fehler im Design. Dann beginnen Sie, die Konsequenzen davon zu analysieren. – SChepurin

0

Cheating Complier wird die Konsequenzen tragen.

struct Foo 
{ 
    int i; 

    Foo(int a):i(a){} 

    void foo (void) const 
    { 
     Foo* pointer = const_cast<Foo*>(this); 
     pointer->i = 0; 
    } 

    bool operator<(const Foo& rhs) const{ 
     return i<rhs.i; 
    } 
}; 

#include <map> 

int main (void) 
{ 
    std::map<Foo,int> kk; 

    for(int i=0;i<10;++i){ 
     kk.insert(std::make_pair(Foo(i),i)); 
    } 

    std::map<Foo,int>::iterator ite = kk.find(Foo(4)); 
    const Foo& foo4 = ite->first; 
    foo4.foo(); 

    ite = kk.find(Foo(4)); 
    const Foo& tmp = ite->first; // crack 

    return 0; 
} 

Programm wird bei knacken "const Foo & tmp = ite-> zuerst;"