2010-04-20 23 views
36

Als eine allgemeine Regel wird es sehr häufig als eine schlechte Praxis betrachtet, const_cast<>() in C++ - Code zu verwenden, da es (meistens) einen Fehler im Design offenbart. Korrekte Verwendung (en) von const_cast <>

Während ich völlig damit einverstanden, ich aber frage mich, was sind die Fälle const_cast<>() wurden verwendet, ist ok und die einzige Lösung.

Könntest du mir bitte ein paar Beispiele nennen, die du kennst?

Vielen Dank.

Antwort

16

const_cast auch volatile Modifikatoren, zu entfernen, wie in diesem (controversed) Artikel in die Praxis umgesetzt:

http://www.drdobbs.com/184403766

+0

Ich habe gerade etwas Großartiges gelernt! Vielen Dank ! – ereOn

+0

ich auch, +1, danke! – Sanish

25

es ziemlich viel ist ausschließlich mit Legacy-APIs verwendet werden, die nicht korrekt, dh mit einer Funktion const sind Sie nicht, dass hat nicht const Schnittstelle tatsächlich ändert, aber nichts an der Schnittstelle

0

mutieren Ja natürlich, wenn dein calling code das du nicht ändern kannst und nicht const korrekt ist. Es sollte beachtet werden, dass Sie es nur bei Aufrufen von Funktionen verwenden sollten, von denen Sie sicher wissen, dass sie Ihre Daten nicht verändern werden!

10

Ich stimme Ihrer Aussage zu, dass sie normalerweise verwendet wird, weil Sie einen "Designfehler" verbergen müssen.

IME eines der typischen Anwendungsszenarien ist, wenn Sie versuchen, C++ mit vorhandenem C-Code zu verbinden. Viele vorhandene C-Code nimmt C-Zeichenfolgen als char *, auch wenn die Zeichenfolge nicht geändert wird, während sie in der Regel als etwas dargestellt werden, das in C++ zu einem const char * konvertiert. Das ist eine Impedanzabweichung zwischen den beiden Sprachen, die Sie normalerweise mit einem const_cast lösen würden. Natürlich sollten Sie besser sein sehr sicher, dass der Code, den Sie mit Schnittstellen sind keine süßen Ideen über die Änderung der Daten, die gerade übergeben wird.

Ich würde sagen, dass es ein Code riecht in neu geschrieben Code, aber für die Schnittstelle mit älteren C-und C++ - Code ist es ein notwendiges Übel. Nichtsdestoweniger würde ich sehr vorsichtig sein von Code, der const_cast für alle Nicht-POD-Objekte erfordert, da dies normalerweise ein Problem ist, das auf der Design-Ebene und nicht auf der Code-Ebene gelöst werden sollte.

2

Eine sehr berechtigte Verwendung dafür ist, wenn Sie sowohl eine const und nicht const api (für const und nicht const-Objekte bezeichnet), wie in

class Bar { 
    const SomeType& foo() const; 
    SomeType& foo(); 
} 

Dann, da wir nicht wollen, um den Code duplizieren in beiden Funktionen oft wir

class Bar { 
    SomeType& foo() { 
     //Actual implementation 
    } 
    const SomeType& foo() const { 
     return const_cast<Bar*>(this)->foo(); 
    } 
}; 

verwenden Dies ist natürlich, dass foo unter der Annahme, etwas nicht tun, die die const Semantik verletzt.

+2

Sie haben das rückwärts und es kann zu undefiniertem Verhalten führen. – GManNickG

+0

Pflege um zu erarbeiten? – Jasmeet

+3

Die Sorge ist, dass die nicht-const-Version von 'foo'' this' modifizieren könnte, und so ist es "unsicher", sie für ein const-Objekt aufzurufen, das Sie in non-const umgewandelt haben. Es ist "sicher", eine konstante Elementfunktion für ein nicht-konstantes Objekt aufzurufen, daher ist GMans Version vorzuziehen. GMans Version kann jedoch auch zu einem nicht definierten Verhalten führen, wenn der Client den zurückgegebenen Wert ändert, als ich seine Antwort kommentierte. –

16

Wie andere gesagt haben, ist sein Hauptzweck, const von Objekten zu entfernen, um nicht-const korrekte Funktionen zu übergeben, die Sie wissen, wird das Argument nicht ändern.

Es gibt einen Trick (von Meyers?) Code Doppelarbeit zu vermeiden, und es geht so:

struct foo 
{ 
    const return_type& get(void) const 
    { 
     // fancy pants code that you definitely 
     // don't want to repeat 

     return theValue; // and got it 
    } 

    return_type& get(void) 
    { 
     // well-defined: Add const to *this, 
     // call the const version, then 
     // const-cast to remove const (because 
     // *this is non-const, this is ok) 
     return const_cast<return_type&>(static_cast<const foo&>(*this).get()); 
    } 
}; 
+7

Ich denke, dieser Trick ist fast immer schlimmer als den Inhalt von 'get() const' in 'get()' zu duplizieren. In den Fällen, in denen dies besser ist als Kopieren und Einfügen, wäre ein Template-Helfer (einmal für const und einmal für nicht-const) instanziiert, da der Compiler dann überprüfen könnte, ob der Code wirklich etwas modifizierbar zurückgibt in dem Fall, in dem "dies" modifizierbar ist. Es könnte nicht sein, es könnte manchmal einen Verweis auf eine "const" globale Variable zurückgeben, so dass dieser Trick Sie zwingt, die const-Korrektheit von fancy pants Code manuell zu überprüfen. Schlecht. –

+1

@Steve: Ich würde lieber diese Kopie einfügen. In dem speziellen Fall, in dem dieser Trick nicht funktioniert, benutze ihn nicht. – GManNickG

+1

Was ist, wenn der Code "fancy pants" 0 Zeilen ist und "get" nur ein Datenelement zurückgibt? Würdest du dann Copy-Paste vermeiden? Ich behaupte, dass es keine guten Fälle für diesen Trick gibt.Entweder ist der Code einfach genug, um ihn zu kopieren oder einzufügen, oder es ist zu komplex, um ihn manuell für die Korrektheit zu analysieren. Es gibt keinen Mittelweg, der zu viel ist, um kopiert zu werden, aber wenig genug, dass Sie keine automatisierte Const-Korrektheit wollen. In Meyers Beispiel IIRC ist der fancy-pants Code ein bounds-check: also setze den Check in eine Hilfsfunktion, genauso wie wir normalerweise Code teilen ;-) –

4

Ein legitimes Verwenden Sie (meiner Meinung nach) mit std::set Iteratoren. Sie sind immer const, um das Ändern des im Satz verwendeten Schlüssels zu verhindern. Das Ändern des Schlüssels würde die interne Struktur des Satzes zerstören und zu undefiniertem Verhalten führen.

Solange jedoch der Schlüssel nicht geändert wird, ist es sicher, andere Daten im Objekt zu ändern.

Angenommen, Sie haben einen std::set wie dieses:

std::set<MyObject> some_set; 

Und eine Klasse wie folgt aus:

class MyObject { 
    public: 
     MyObject(const std::string &key) 
      : key_(key) {} 

     bool operator<(const MyObject &other) const { 
      return key_ < other.key_; 
     } 

    private: 
     // ... 
     // <some other data> 
     // ... 

     const std::string key_; 
}; 

In dem obigen Beispiel der Schlüssel ist bereits const, also auch wenn Sie Ändern Sie das Objekt, Sie können die interne Struktur des Satzes nicht brechen.

Normalerweise kann man nur erhalten eine const Referenz aus einem Satz Iterator:

const MyObject &object = *some_set_iterator; 

Aber da der Schlüssel const ist, dann ist es sicher const_cast die dereferenzierte Iterator:

MyObject &object = const_cast<MyObject &>(*some_set_iterator); 
Verwandte Themen