1

私はこの次のコードを持っています

size_t returnSize(const char* s)
{
       string string(s);
       return string.size();
};

size_t returnSize(const int& i)
{
       return sizeof(i);
};


template<typename T>
vector<char> Serialize(const T& t)
{
    T* pt = new T(t);
    vector<char> CasttoChar;

    for (int i =0 ;i<returnSize(t);i++)
    {
        CasttoChar.push_back(reinterpret_cast<const char*>(pt)[i]);
    }
    delete pt;
    return CasttoChar;
};
template<typename T>
T DeSerialize(const vector<char> cstr)
{
    T* a = (T*)(&cstr[0]);

    return *a;
}

int _tmain(int argc, _TCHAR* argv[])
{
    int x = 97;
    vector<char> c = Serialize(x);
    cout << DeSerialize<int>(c) << endl;

    string k = "blabla";
    vector<char> c3 = Serialize(k.c_str());
    cout << DeSerialize<const char*>(c3) << endl;

    system("PAUSE");
    return EXIT_SUCCESS;
}

//output is 
//97
//blabla

この回線はT* a = (T*)(&cstr[0]);安全ですか?

また、reinterpret_cast<T*>(&cstr[0]);代わりに試してみましたがT* a = (T*)(&cstr[0]);、コンパイラは const char* を int* に変換できないと不平を言いました。では、なぜ C スタイルのキャストが機能するのでしょうか。

4

5 に答える 5

3

規格参照

reinterpret_cast が失敗するのはなぜですか?

5.2.10 キャストの再解釈 [expr.reinterpret.cast]

reinterpret_cast 演算子は constness をキャストしてはなりません (5.2.11)。整数型、列挙型、ポインター型、またはメンバーへのポインター型の式は、明示的に独自の型に変換できます。そのようなキャストは、そのオペランドの値を生成します。

Cキャストを使用する必要がありますか? いいえ。C++ キャストの代わりに C キャストを使用することは、常に安全ではありません。UB であるオブジェクトの定数を削除しようとしています。reinterpret_cast を使用すると、実際にこのエラーをトラップし、コンパイル時に潜在的な落とし穴についてアドバイスします。

const_castこの状況で実際に使用する必要があります。constオブジェクトを非constオブジェクトに変換する唯一の正当な方法

しかし、なぜCキャストが機能するのですか

質問から受け入れられた回答からの引用static_cast、dynamic_cast、および reinterpret_cast を使用する必要があるのはいつですか?

C スタイルのキャストは、成功する次の最初のものとして定義されます。

const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast

幸いなことに、それはconst_cast最初に試みます。

于 2013-01-13T09:27:15.307 に答える
2

C スタイルのキャストが機能するのは、キャストを成功させるために多くのステップが必要だからです。次のうち、成功した最初のものを使用します。

const_cast
static_cast
static_cast + const_cast
reinterpret_cast
reinterpret_cast + const_cast

この場合、 to の後にreinterpret_casttoconst int *が続く、最も「強力な」キャストを実行しconst_castていint*ます。

const-ness をキャストしているため、reinterpret_cast単独ではコンパイルされません。const_castにキャストするには が必要ですint*。ただし、reinterpret_casttoconst int*を実行しても問題ありません。

余談ですが、逆シリアル化するユーザー定義型がパディングされないようにするためにコンパイラ拡張機能を使用していない限り、あなたがしていることは一般的に安全ではありません。

于 2013-01-13T09:25:50.913 に答える
0

申し訳ありませんが、コードはいくつかの点で壊れており、キャストはその 1 つにすぎません。キャストに関しては、単純な int などではなく、コンストラクターを必要とするものでベクターから/への変換を使用するとすぐに失敗します。いずれにせよ、残念ながら から への 2 段階の変換が必要ですchar const*void const*T const*

さて、他の問題:

  • サイズがゼロの文字列ですべてを試してください。これで、実際の質問にも完全に答えられるはずです。いいえ、安全ではありません。
  • から char へのポインタを返していますDeSerialize<char const*>()。このポインタは、指定されたベクトルが所有するメモリを指し、値によって渡され、その関数から戻った後は存在しなくなります! うまくいくように見えるのは純粋な運です。
  • 関数からどうにかして a を返すことができたとしても、char const*そのメモリの所有者は誰なのかを考えてみてください。ポイントは、この所有者もメモリを解放する必要があるということです。std::stringテンプレートの特殊化を使用して、char const*バリアントを使用してコンパイルしないようにすることを検討してください。
  • 一般に、このコードが本格的であることを意味する場合は、単体テストの追加を開始してください。今は遅くなるかもしれませんが、移動中のエラーを回避するため、全体的に時間を節約できます. 「テスト駆動開発」で検索してください。
  • 文字列が NUL で終了することを保証するものは何もありません。
  • 必要がない限り、new/delete を使用しないでください。「プレーンな」スタック変数を優先してください。その場合は、(push_back() からの) 例外が発生した場合にメモリを適切に解放するように注意してください。auto_ptr (C++98) または unique_ptr (C++11) を使用して、メモリが正しく解放されるようにします。
于 2013-01-13T10:23:34.633 に答える
0

c++ での C スタイルのキャストは、const の削除や任意の型の変更を防ぐチェックを通過するため、正確には良い考えではありません。コードをそのまま動作させたい場合は、最初に const_cast を実行してから reinterpret_cast を実行する必要がありますが、実際にはconst のキャストを避けるようにしてください。reinterpret_cast を使用して警告を回避するには、 a を as として宣言するだけconst T*です。

于 2013-01-13T09:25:32.397 に答える
0

C++ キャストに固執します。うまくいかなかった理由は、reinterpret_castconstness を捨てていたからです。これはクールではありません。そのために a を使用するconst_cast必要があり、そうすべきではありません。C キャストはこれを無視します。

そうは言っても、ここで何を達成しようとしていますか?char効果的に配列にキャストしmemcpy、効率を上げずに ing します。

于 2013-01-13T09:26:29.633 に答える