4

私はこれを何度も見て、特にさまざまなスレッド実装でC++を使用しました。これを行うことの落とし穴/問題があるかどうか私は疑問に思いますか?void *にキャストして再び戻るときに、エラーまたは未定義の状態に遭遇する可能性がある方法はありますか?そのような問題がある場合、どのように解決する必要がありますか?

ありがとうございました。

4

7 に答える 7

16

これは完全に有効です。これが標準がそれについて言わなければならないことです:

§4.10ポインタ変換

2オブジェクトタイプである「pointertocv」タイプの右辺値は、 pointertocv」タイプの右辺値に変換できます。「 pointertocv」を「pointertocv 」に変換した結果は、オブジェクトがタイプ(つまり、基本クラスのサブオブジェクトではありません)。TT void T voidTT

つまり、クラスへのポインタをvoidポインタに変換できます。と ...

§5.2.9静的キャスト

10タイプ「pointertocv」の右辺値は voidオブジェクトタイプへのポインターに明示的に変換できます。「 pointertocv 」に変換され、元のポインタ型に戻るオブジェクトへvoidのポインタ型の値は、元の値になります。

static_castこれは、voidポインタを元のクラスポインタに戻すために使用できることを意味します。

それが役に立てば幸い。幸運を!

于 2013-09-21T05:31:57.620 に答える
6

C ++では、次の場所に到達する ために静的キャストは必要ありませんvoid*

int main()
{
    CFoo* foo = new CFoo;
    void* dt = foo;
    tfunc(dt); // or tfunc(foo);

    return 0;
}

注意:キャストtfunc()必要なという点で、の実装は非常に正しいです。

于 2014-09-11T13:00:02.367 に答える
5

私はC++でキャストするのを見たことがありません。void*これは、C++で積極的に回避されているCの慣習です。

void*すべてのタイプの安全性を取り除くために鋳造します。

reinterpret_castまたはを使用static_castしてポインタ型から同じポインタ型にキャストしたりvoid*、同じポインタ型にキャストしたりする場合、実際には、結果が明確に定義されることが標準によって保証されています

void*正しいタイプが何であるかがわからなくなったため、間違ったタイプにキャストする可能性があるという危険があります。

于 2012-09-05T06:12:30.990 に答える
3

これを行うことの落とし穴/問題があるかどうか私は疑問に思いますか?

バックを特定のタイプにキャストするときは、絶対に確認する必要がありvoid*ます。そうしないと、未定義の動作と潜在的な災害が発生します。一度使用すると、型の安全性void *が失われます。aが実際に指している型を追跡することは困難であり、型キャスト先の型を実際に指していることを保証または判断する方法はありません。void *

void *にキャストして再び戻るときに、エラーまたは未定義の状態に遭遇する可能性がある方法はありますか?

はい、で述べたシナリオ#1

そのような問題がある場合、どのように解決する必要がありますか?

void *C ++で完全に使用することは避け、代わりにテンプレートと継承を使用してください。
Cでは、特定の状況で絶対に必要になる場合がありますが、使用を最小限に抑えるようにしてください。
結論として、
C / C ++を使用すると、足で自分を撃つことができます。そうするかどうかはあなた次第です。

于 2012-09-05T06:06:47.763 に答える
2

標準で許可されているのは、が与えられた場合だけA* paです(A*)(void*)pA == pA。結果

void* pv = pA;
A* pA2 = (A*)pv;
pA2->anything ...

と同じになりますpA->anything ...

他のすべては「定義されていません」、広告は-実際には-何らかの形で実装に依存しています。

私の経験に基づいて、ここにいくつかの既知の落とし穴があります:

  • A派生形式B、、pAおよびpBであると考えA*てくださいB*pB=pAのベースをpB指すようにしAます。それはそれを意味するものpBpAはなく、同じアドレスです。したがって、pB = (B*)(void*)pA実際には他の場所をAに向けることができます(ただし、単一の継承オブジェクトは通常、同じオリジンを共有して実装されるため、正常に機能するようです)
  • pB同じことが逆です。実際にを指していると仮定するとApA = (A*)(void*)pB必ずしもAオブジェクトを正しく指しているとは限りません。正しい方法はpA = static_cast<A*>(pB);
  • 上記のポイントがほとんどの単一継承実装で機能する場合、最初の継承以外のベースの複数継承では機能しません。が空でないclass A: public Z, public B { ... };場合、サブコンポーネントは同じAアドレスを持たないことを考慮してください。(そしてC ++の多重継承はiostreamがどこにでもあります)ZAB
  • プラットフォームにも依存する場合があります:((char*)(void*)pI整数pIを指す場合)は「ifin(-128 .. + 127)」と同じではありません*pI*pIリトルエンディアンのマシンにのみ存在します)

一般に、タイプ間の変換がアドレスの解釈方法を変更するだけで機能するとは限りません

于 2012-09-05T07:26:14.540 に答える
1

呼び出し元にデータを返すためにvoidポインターを使用するドライバーなどの多くの関数を知っていますが、スキーマはほとんど同じです。

int requestSomeData(int kindOfData, void * buffer, int bufferSize);

この関数は、パラメーターとしてさまざまなデータ型をとることができます。彼らがしていることは、バッファサイズをパラメータとして使用して、書き込みを行わないメモリの場所への書き込みを回避することです。bufferSizeが一致しないか、返されるデータよりも小さい場合、関数は代わりにエラーコードを返します。

とにかく:コードを書く前に、それらを使用しないか、3つ考えてください。

于 2012-09-05T06:10:34.897 に答える
1

これは有効ですか?

はい、それは標準§5.2.9.7に従って有効です

タイプ「pointertocv1void」のprvalueは、タイプ「pointer to cv2 T」のprvalueに変換できます。ここで、Tはオブジェクトタイプであり、cv2はcv1と同じかそれ以上のcv-qualificationです。nullポインター値は、宛先タイプのnullポインター値に変換されます。「pointertocvvoid」に変換されたオブジェクトへのポインタ型の値は、おそらく異なるcv修飾で、元の値を持つ必要があります。[ 例:

T* p1 = new T;
const T* p2 = static_cast<const T*>(static_cast<void*>(p1));
bool b = p1 == p2; // b will have the value true.
于 2013-09-21T05:30:38.260 に答える