64

次のコード(およびをVirtualAlloc()返すというvoid*事実)を考慮してください。

BYTE* pbNext = reinterpret_cast<BYTE*>(
    VirtualAlloc(NULL, cbAlloc, MEM_COMMIT, PAGE_READWRITE));

なぜreinterpret_cast代わりに選ばれるのstatic_castですか?

reinterpret_cast以前は、整数型(egなど)との間でポインタをキャストする場合は問題ないと思っていDWORD_PTRましたが、aからaにキャストvoid*する場合は、問題BYTE*ありませんstatic_castか?

この特定のケースに(微妙な?)違いはありますか、それとも両方とも有効なポインターキャストですか?

C ++標準にはこの場合の優先順位があり、他の方法ではなく方法を提案していますか?

4

3 に答える 3

53

基本型への変換可能なポインターの場合、両方のキャストは同じ意味を持ちます。だからあなたは正しいですそれstatic_castは大丈夫です

一部のポインタタイプ間で変換する場合、ポインタに保持されている特定のメモリアドレスを変更する必要がある可能性があります

ここで2つのキャストが異なります。 static_cast適切な調整を行います。 reinterpret_castしない。

そのため、それが望ましいことがわかっているstatic_cast場合を除いて、ポインタ型間を移動することをお勧めします。 reinterpret_cast

于 2013-03-22T20:06:46.767 に答える
30

あなたがすべきstatic_castです。暗黙の変換を元に戻す場合に使用します。static_cast

ただし、この特定のケースでは、から変換しているため、違いはありませんvoid*。しかし、一般的に、reinterpret_cast2つのオブジェクトポインタ間のingは(§5.2.10/ 7)と定義されています。

オブジェクトポインタは、異なるタイプのオブジェクトポインタに明示的に変換できます。タイプ「pointerto」のprvaluevがタイプ「 pointertocv 」T1に変換されると、結果は、とが両方とも標準レイアウトタイプであり、の配置要件がのそれらよりも厳密でない場合、またはいずれかのタイプが。タイプ「pointerto」のprvalueをタイプ「pointerto 」(ここで、およびはオブジェクトタイプであり、の配置要件はの要件よりも厳密ではありません)に変換し、元のタイプに戻すと、元のポインタ値が生成されます。他のそのようなポインタ変換の結果は特定されていません。T2static_cast<cv T2*>(static_cast<cv void*>(v))T1T2T2T1voidT1T2T1T2T2T1

強調鉱山。T1あなたはすでにですので、 invoid*へのキャストは何もしません。これは一般的に真実ではありません、それはドリュー・ドーマンが言っていることです:void*reinterpret_cast

#include <iostream>

template <typename T>
void print_pointer(const volatile T* ptr)
{
    // this is needed by oversight in the standard
    std::cout << static_cast<void*>(const_cast<T*>(ptr)) << std::endl;
}

struct base_a {};
struct base_b {};
struct derived : base_a, base_b {};

int main()
{
    derived d;

    base_b* b = &d; // implicit cast

    // undo implicit cast with static_cast
    derived* x = static_cast<derived*>(b);

    // reinterpret the value with reinterpret_cast
    derived* y = reinterpret_cast<derived*>(b);

    print_pointer(&d);
    print_pointer(x);
    print_pointer(y);
}

出力:

00CBFD5B
00CBFD5B
00CBFD5C

y(実際にはを指していないためderived、それを使用することは未定義の動作であることに注意してください。)

ここでreinterpret_castは、を通過するため、別の値を考え出しますvoid*static_castこれが、可能な場合と必要な場合に使用する必要がある理由ですreinterpret_cast

于 2013-03-22T20:18:46.120 に答える
8

static_castとの間でポインタをキャストするために使用するとvoid*、アドレスが保持されることが保証されます。

reinterpret_cast一方、ある型から別の型にポインタをキャストし、元の型に戻すと、アドレスが保持されることが保証されます。

ほとんどの実装では、これらのいずれかを使用しても同じ結果が得られますが、static_cast推奨されるはずです。

そして、C++11私が覚えているのは、 reinterpret_castforを使用することvoid*は明確に定義された動作をすることです。それ以前は、この動作は禁止されていました。

It is not permitted to use reinterpret_cast to convert between pointers to object type and pointers to void.

提案された決議(2010年8月):

5.2.10[expr.reinterpret.cast]段落7を次のように変更します。

オブジェクトポインタは、別のタイプのオブジェクトポインタに明示的に変換できます。タイプ「pointertoT1」のprvaluevがタイプ「pointertocvT2」に変換されると、T1とT2の両方が標準レイアウトタイプ(3.9 [basic.types])の場合、結果はstatic_cast(static_cast(v))になります。 )およびT2のアライメント要件は、T1のアライメント要件よりも厳密ではありません。または、いずれかのタイプが無効である場合。

タイプ「pointertoT1」のprvalueをタイプ「pointertoT2」(T1とT2はオブジェクトタイプであり、T2のアライメント要件はT1の要件よりも厳密ではない)に変換して元のタイプに戻すと、元のタイプが生成されます。ポインタ値。他のそのようなポインタ変換の結果は指定されていません。

詳細はこちら

リンクをくれたJesseGoodに感謝します。

于 2013-03-22T20:09:31.577 に答える