7

C++ では、const void *関数の引数の型に a を使用する価値はありvoid *ますか? a は不透明なので、ユーザーがを行う場合void *以外に変更のリスクはありますか? 問題を回避するために特殊化を提供する共有ポインタ用のユーティリティ テンプレート クラスを使用していたが、特殊化が提供されていなかったので、これは単なる見落としであったのか、それとも決して必要ではないのでしょうか?reinterpret_castconst_castconst void *voidvoid &const void

4

6 に答える 6

9

これは、他のポインター型で提供されるのと同じ利点を提供します。-ness を明示的にconstキャストしない限り、指されているものを変更することはできません。constインターフェイスでconst void*は、渡すものは何でも読み取れるが書き込まれないというクライアント コードへのサインです。たとえば、次のstd::memcpyように宣言されています

void *memcpy(void *dest, const void *src, std::size_t count);

に読み書きすることsrcを通知しdestます。もちろん、それが実際に C++ で実装された場合 (可能ですが、ありそうにありません)、両方のポインターを他の型にキャストする必要があります。

これで「何の得にもならない」と感じたら、それは明らかに価値のないconstキーワードそのものです。

于 2012-07-09T15:46:24.293 に答える
4

memcpyは、2 つのポインター パラメーター (onevoid*と other ) を取りますconst void*const char*2 番目のパラメーターは(または他の const オブジェクト型へのポインター) 引数から暗黙的に変換できますが、最初のパラメーターは変換できません。

暗黙的な変換が存在しないことが値です。これにより、ユーザーは、意図的に const を破棄するのではなく、必要な (ありそうもない) イベントで意図的に const を破棄するようになります。

次にmemcpy、または同様の関数の実装内で、プログラマーは、その参照先を変更しようとする前に、パラメーターをconst_castC スタイルでキャストする必要があります。const 以外のパラメーターを使用して、そのリファランドを変更できますconst void*static_castあなたが書く必要があるキャストの種類は、うまくいけば、あなたがやっていることは賢明であるかどうかについて何かを教えてくれます.

あなたの shared_ptr ヘルパー関数がvoid特別に扱う必要がある場合、cv 修飾されたすべてを特別に扱う必要があると思いますvoid。つまり、 、 、 、 の 4 つvoidconst voidケースvolatile voidですconst volatile void。しかし、関数のユーザーが過去に で試してみて、shared_ptr<void>うまくいかなかったと不満を述べたが、 で試したことがない場合shared_ptr<const void>、問題は発生していない可能性があります。

たぶんshared_ptr<void>、それが現れていないほど十分に異常です。誰かが最終的に正しい型を復元するときはいつでも、正しい修飾子も復元することに基づいて、を使用するような人はshared_ptr<void>cv 修飾子を捨てることを気にしない傾向があるかもしれません。

考えてみてください-shared_ptr<const void>まったく機能しますか、それともデリータを呼び出すコードでからへshared_ptrの暗黙的な変換が必要ですか? を使用したことがあるかどうかは覚えていません。T*void*shared_ptr<const T>

于 2012-07-09T15:47:06.767 に答える
3

の「ドキュメンテーション値」を忘れないでくださいconst。誰かがいつでもそれを捨てることができますが、constは、指している対象がポインターを介して変更されるべきではないという本来の意図を示す役割を果たします。 const_cast(さらにreinterpret_cast言えば)常に注意して使用する必要があり、必要な場合はプログラマーを一時停止する必要があります。

于 2012-07-09T15:46:51.853 に答える
2

はい、const常にあるのと同じ利点 (のいくつか) があります:コンテンツが変更されるべきではないという事実を文書化します。

次のコードを想像してください。

int const object = some_value();
some_function(&object);

この呼び出しは、関数の引数が として宣言されている場合にのみコンパイルされvoid const*ます。それ以外の場合、クライアントはconst_castconstness をキャストするために が必要になります。もちろん、クライアントにこの不便さを感じてほしくないし、(constness を捨てて) データについて嘘をつくことも望んでいません。

于 2012-07-09T15:48:19.267 に答える
1

すべての用途と同様に、const2 つの目的を果たします。関数の実装では、コンパイラが誤用を検出するのに役立ちます。これは、言及したように、const_cast(またはCスタイルのキャスト)によって強制および沈黙させることができます。

しかしconst、2 番目の目的を果たします。オブジェクトが変更されないという約束を提供し、そうすることで、ユーザーが const オブジェクトへのポインターを渡すことができるようになり (約束を守るという前提で)、関数を効果的に幅広く使用できるようになります。これは、次の簡単な例で確認できます。

void foo( const void* );
void bar( void* );
int main() {
    const int value = 10;
    foo( &value );          // correct, the function promises not to modify the value
    //bar( &value );        // error, this would break const correctness
}
于 2012-07-09T15:51:07.807 に答える
1

コードを「自己文書化」することにはまだ利点があります。

store_pod(const void* data, std::size_t bytes);

コメントなしで指定すると、ポイント先のデータが変更されないことがわかります。

また、その約束を破るには、関数が aと a のconst両方を実行する必要があることに注意してください。const_castreinterpret_cast

于 2012-07-09T15:48:38.383 に答える