web-dev-qa-db-ja.com

const_castは安全ですか?

_const_cast_についてあまり情報が見つかりません。 (Stack Overflowで)見つけられる唯一の情報は次のとおりです。

const_cast<>()は、変数のconst(ness)(またはvolatile-ness)を追加/削除するために使用されます。

これは私を緊張させます。 _const_cast_を使用すると、予期しない動作を引き起こす可能性がありますか?もしそうなら、何?

または、_const_cast_をいつ使用してもよいですか?

87
Mag Roader

const_castは、元は非constであった変数をキャストしている場合にのみ安全です。たとえば、const char *のパラメーターを受け取る関数があり、変更可能なchar *を渡す場合、そのパラメーターをconst_castに戻し、char *に戻して変更しても安全です。ただし、元の変数が実際にconstであった場合、const_castを使用すると、未定義の動作が発生します。

void func(const char *param, size_t sz, bool modify)
{
    if(modify)
        strncpy(const_cast<char *>(param), sz, "new string");
    printf("param: %s\n", param);
}

...

char buffer[16];
const char *unmodifiable = "string constant";
func(buffer, sizeof(buffer), true);  // OK
func(unmodifiable, strlen(unmodifiable), false); // OK
func(unmodifiable, strlen(unmodifiable), true);  // UNDEFINED BEHAVIOR
85
Adam Rosenfield

Const_castが安全で便利な2つの状況を考えることができます(他の有効なケースがあるかもしれません)。

1つは、constインスタンス、参照、またはポインターがあり、const-correctではないAPIにポインターまたは参照を渡したいが、CERTAINがオブジェクトを変更しない場合です。ポインターをconst_castしてAPIに渡すと、実際には何も変わらないことを信頼できます。例えば:

void log(char* text);   // Won't change text -- just const-incorrect

void my_func(const std::string& message)
{
    log(const_cast<char*>(&message.c_str()));
}

もう1つは、「mutable」を実装しない古いコンパイラを使用しており、論理的にconstであるがビット単位のconstではないクラスを作成する場合です。 constメソッド内で「this」をconst_castし、クラスのメンバーを変更できます。

class MyClass
{
    char cached_data[10000]; // should be mutable
    bool cache_dirty;        // should also be mutable

  public:

    char getData(int index) const
    {
        if (cache_dirty)
        {
          MyClass* thisptr = const_cast<MyClass*>(this);
          update_cache(thisptr->cached_data);
        }
        return cached_data[index];
    }
};
34
Fred Larson

Const_castについて見つけることができるonly情報だとは信じ難い。 2番目のGoogleヒット からの引用:

Constとして明示的に宣言されているオブジェクトのconstnessをキャストし、それを変更しようとすると、結果は未定義です。

ただし、constとして明示的に宣言されていないオブジェクトのconstnessを捨てる場合は、安全に変更できます。

22
Rob Kennedy

アダムの言うこと。 const_castが役立つ別の例:

struct sample {
    T& getT() { 
        return const_cast<T&>(static_cast<const sample*>(this)->getT()); 
    }

    const T& getT() const { 
       /* possibly much code here */
       return t; 
    }

    T t;
};

最初にthisが指す型にconstを追加し、次にgetTのc​​onstバージョンを呼び出し、戻り型からconstを削除します。これは、t非constでなければなりません(そうでなければ、getTの非constバージョンを呼び出すことはできませんでした)。これは、関数本体が大きく、冗長なコードを避けたい場合に非常に役立ちます。

短い答えはノーです、それは安全ではありません。

長い答えは、あなたがそれを使用するのに十分知っているなら、それは安全でなければならないということです。

あなたがキャストしているとき、あなたが本質的に言っているのは、「コンパイラが知らないことを知っている」ということです。 const_castの場合、あなたが言っているのは、「このメソッドは非const参照またはポインターを受け取りますが、渡すパラメーターを変更しないことはわかっています。」

そのため、キャストを使用して知っていると主張していることを実際に知っている場合は、キャストを使用しても問題ありません。

9
JohnMcG

コンパイラがconstであると考えていたものを変更し始めると、スレッドの安全性が失われる可能性があります。

5
Matt Cruikshank