web-dev-qa-db-ja.com

ポインター型をキャストする適切な方法

次のコード (および VirtualAlloc()void* を返すという事実を考慮する):

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

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

reinterpret_castは大丈夫だと思っていました。整数型(例:DWORD_PTR)との間でポインターをキャストしますが、void*からBYTE*にキャストするには、static_castで問題ありませんか?

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

C++標準には、この場合の設定があり、他の方法の代わりに方法を提案していますか?

46
Mr.C64

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

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

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

そのため、static_castポインタタイプ間know that reinterpret_castが必要です。

38
Drew Dormann

_static_cast_する必要があります。 暗黙の変換を取り消す場合は_static_cast_を使用します。

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

オブジェクトポインターは、異なるタイプのオブジェクトポインターに明示的に変換できます。タイプ「_T1_へのポインター」のprvalue vがタイプ "cv _T2_へのポインター"に変換される場合、結果はstatic_cast<cv T2*>(static_cast<cv void*>(v))_T1_と_T2_の両方が標準レイアウト型であり、_T2_のアライメント要件が_T1_、またはいずれかのタイプがvoidの場合。 「ポインターへの_T1_」型のprvalueから「_T2_へのポインター」型への変換(ここで_T1_および_T2_はオブジェクト型であり、アライメント要件は_T2_は_T1_)より厳密ではなく、元の型に戻すと元のポインター値が返されます。他のそのようなポインター変換の結果は指定されていません。

強調鉱山。 _T1_はすでに_void*_であるため、_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_を使用する必要がある理由です。

23
GManNickG