2009-08-20 9 views
4

Ich habeWie Zeiger werfen Foo Foo ** const ** in C++

class Fred 
{ 
public: 
    void inspect() const {}; 
    void modify(){}; 
}; 

int main() 
{ 
const Fred x = Fred(); 
Fred* p1; 
const Fred** q1 = reinterpret_cast<const Fred**>(&p1); 
*q1 = &x; 
p1->inspect(); 
p1->modify(); 
} 

Wie wäre es möglich, die const Fred ** q1 = & p1 über Zeiger-Casting zu tun?

(Ich habe gerade Lesung, dass dies möglich sein könnte)

Dank für Ihre Antworten danken. Die const_cast arbeitet in der Tat für Objekte

#include <iostream> 
#include <stdio.h> 
using namespace std; 

class Fred 
{ 
int a; 

public: 
Fred(){}; 
Fred(int a_input) 
{ 
a = a_input; 
}; 

void inspect() const 
{ 
cout << "Inspect called"<< endl; 
cout << "Value is "; 
cout << a << endl; 
}; 

void modify() 
{ 
cout << "Modify called" << endl; 
a++; 
}; 

}; 

int main() 
{ 
const Fred x = Fred(7); 
const Fred* q1 = &x; 
Fred* p1 = const_cast<Fred*>(q1); 
p1->inspect(); 
p1->modify(); 
p1->inspect(); 
x.inspect(); 
*p1 = Fred(10); 
p1->inspect(); 
} 

Inspect called 
Value is 7 
Modify called 
Inspect called 
Value is 8 
Inspect called 
Value is 8 
Inspect called 
Value is 10 
Inspect called 
Value is 10 

gibt jedoch für vordefinierte Typen funktioniert es nicht:

int main() 
{ 
const double a1 = 1.2; 
const double* b1 = &a1; 
cout << "a1 is " << (*b1) << endl; 
cout << "b1 is " << b1 << endl; 
double* c1 = const_cast<double*>(&a1); 
cout << "b1 is " << b1 << endl; 
cout << "c1 is " << c1 << endl; 

double* d1 = static_cast<double*>(static_cast<void*>(c1)); 
cout << "d1 is " << d1 << endl; 
cout<< "*d1 is " << *d1 << endl; 

*d1=7.3; 

cout<< "*d1 is " << *d1 << endl; 
cout<< "*d1 address is "<< d1 << endl; 
cout << "a1 is " << a1 << endl; 
cout << "a1 address is" << &a1 << endl; 
cout<< "*d1 is " << *d1 << endl; 
cout<< "*d1 address is "<< d1 << endl; 

double f1=a1; 
printf("f1 is %f \n", f1); 
} 

wird dadurch:

a1 is 1.2 
b1 is 0xffbff208 
b1 is 0xffbff208 
c1 is 0xffbff208 
d1 is 0xffbff208 
*d1 is 1.2 
*d1 is 7.3 
*d1 address is 0xffbff208 
a1 is 1.2 
a1 address is0xffbff208 
*d1 is 7.3 
*d1 address is 0xffbff208 
f1 is 1.200000 

Anscheinend das g ++ Der Compiler optimiert so, dass er a1 bei jeder Änderung durch 1,2 ersetzt. Selbst wenn sich sein Wert auf dem Stack geändert hat, ist das egal.

(In meinem Fall hatte ich Probleme mit dem direkten Lesen der * b1, * c1, also musste ich die doppelte statische Besetzung tun - die Reinterpret Cast funktionierte nicht).

Ist es eine Möglichkeit, wirklich a1 zu ändern, "normal" zu kompilieren, also nicht kompilieren ohne die Optimierung (also überhole ich den Optimierungseffekt)?

+1

Danke für die Neuformatierung! Viel einfacher zu lesen! – Toji

+1

Die neue Information, die Sie hinzugefügt haben, ist tatsächlich eine andere Frage. In Zukunft könnte es auch so aussehen (es wird auch mehr Antworten geben). Wie für die Compiler-Optimierungen für die Const-Primitiven: Wenn Sie nicht möchten, dass der Compiler es optimiert, um ... mach es nicht const. Der Punkt von const ist, dem Compiler zu sagen, dass Sie diesen Wert NICHT ändern werden. Wenn Sie danach versuchen, es zu ändern, verletzen Sie den C++ - Standard. Mit anderen Worten, tu es nicht! Noch einmal, wenn Sie beabsichtigen, einen Wert zu ändern, machen Sie es nicht const. Zeitraum. – Toji

Antwort

4

Sie möchten const_cast.

+0

ermöglicht es Ihnen, einen nichtkonstanten Zeiger auf ein const-Objekt zu erstellen, aber jeder Versuch, dieses const-Objekt tatsächlich zu ändern, führt immer noch zu undefiniertem Verhalten. –

16

Dies sollte es tun:

Foo** f; 
const Foo** cf = const_cast<const Foo**>(f); 
9

dies keine gute Idee ist, weil es die Sicherheit verletzt geben. Lassen Sie mich erklären, warum:

Fred* pFred; 
const Fred** ppFred = const_cast<const Fred**>(&p); 

*ppFred = new const Fred; // Now pFred points to a const Fred 

pFred->some_evil_mutating_method(); // can do, since type of *pFred is non-const! 
+2

Sie haben Recht, von dieser Art von Verhalten wegzuwarnen, aber verwechseln Sie bitte nicht "keine gute Idee" mit "nicht möglich". Ersetzen von reinterpret_cast durch const_cast in seinem Code erzeugt perfekt gültiges, kompilierbares C++. – Toji

+2

Yup, habe gerade den Standard überprüft. Meine Schuld - ich hatte nie realisiert, dass const_cast speziell für Zeigerketten klar definiert ist, obwohl es dort inhärent unsicher ist. Ironisch, wenn man bedenkt, dass man allgemein davon ausgeht, dass "const_cast" nur dann unsicher ist, wenn man die Konstanz von einem Objekt, das inhärent const ist, wegwirft, während es in diesem Fall nicht sicher ist, wenn man const zu einem Objekt addiert, das nicht const ist . Es sieht für mich wie eine sehr stinkende Designentscheidung aus, aber ich denke, das ist C++ für dich. Wird die Antwort beheben. –

+0

@Pavel, wenn Sie eine const_cast brauchen, tun Sie etwas potenziell Gefährliches, die sicheren Fälle brauchen die Besetzung nicht. (Beachten Sie, dass es in C sichere Fälle gibt, die eine Besetzung erfordern). – AProgrammer

1

Warum machst du nicht nur :?

const Fred** q1; 
*q1 = p1; 

Oder wollen Sie Konstantheit Verletzung ohne const_cast elide? - Nein, Sir, das geht nicht.

-1

Sie sollten kein Gießen für const Fred** q1 = &p1 als eine nicht-const Fred** kann direkt in seiner Deklaration zu einem const Fred** q1 zugeordnet werden.

+1

Nein, kann es nicht. Probieren Sie es selbst aus - es wird nicht kompiliert ohne eine 'const_cast'. –

0

Sie sollten es nicht tun. Die Tatsache, dass Sie die Konvertierung nicht einfach durchführen können, ist, weil sie die konstante Korrektheit unterbricht (und Ihr Code es ausübt). Unter Verwendung der obigen Empfehlungen wird Ihr Code kompiliert und ruft eine Mutationsmethode für ein konstantes Objekt (letzte Codezeile) auf.

Dies ist nicht empfehlenswert und kann in einigen seltenen Fällen sogar Ihre Anwendung beenden (ein konstantes globales Objekt könnte in einer schreibgeschützten Speicherseite gespeichert werden) oder eine instabile Situation hinterlassen (Sie ändern den internen Zustand eines Objekts) durch Ändern einer konstanten Referenz in ein internes Elementelement, wobei die Objektinvarianten gebrochen werden).

über Ihr Problem: C++ FAQ Lite [18.17]

Verwandte Themen