2

だから私はいくつかの構造体を持っています...

struct myBaseStruct
{
};

struct myDerivedStruct : public myBaseStruct
{
    int a, b, c, d;
    unsigned char* ident;
};

myDerivedStruct* pNewStruct;

...そして、ゼロで終わる文字列を含む一部のデータで「memcpy」できるように、十分なスペースを動的に割り当てたいと考えています。基本構造体のサイズは明らかに '1' であり (0 にはならないためだと思います)、派生構造体のサイズは 20 であり、これは理にかなっているようです (5 x 4)。

したがって、サイズが 29 のデータ バッファーがあります。最初の 16 バイトは int で、残りの 13 バイトは文字列です。

文字列に十分なメモリを pNewStruct に割り当てるにはどうすればよいですか? 理想的には、私は行きたいだけです:

  • pNewStruct に 29 バイトを割り当てます。
  • バッファーから pNewStruct への memcpy;

ありがとう、

4

9 に答える 9

6

C に戻るか、これらのアイデアを放棄して、意図したとおりに実際に C++ を使用します。

  • コンストラクタを使用してメモリを割り当て、デストラクタを使用して削除します。
  • 他のコードをメモリ空間に書き込ませないでください。メモリが確実に割り当てられるようにする関数を作成してください。
  • 独自のコンテナー クラスをローリングするのではなく、std:string または std::vector を使用してデータを保持します。

理想的には、次のように言う必要があります。

myDerivedClass* foo = new myDerivedClass(a, b, c, d, ident);

于 2009-12-16T23:00:34.843 に答える
4

現在の C++ 標準でmyDerivedStructは、基底クラスがあるため、POD ではありません。memcpy何かを入れた結果は未定義です。

C++0x では規則が緩和され、C++98 よりも多くのクラスが POD になると聞きましたが、調べていません。また、非常に多くのコンパイラが POD と互換性のない方法でクラスをレイアウトするとは思えません。空の基本クラスの最適化を行わなかったものにのみ問題があると思います。しかし、そこにあります。

それが POD だった場合、または実装でチャンスをつかみたい場合は、基本的に C の場合と同じように、十分なスペースを使用malloc(sizeof(myStruct)+13)またはnew char[sizeof(myStruct)+13]割り当てることができます。動機は、おそらくメモリと時間のオーバーヘッドを回避することです。クラスにメンバーを配置するだけstd::stringですが、手動のメモリ管理用のコードを作成する必要があります。

于 2009-12-16T23:00:15.953 に答える
3

任意のクラス インスタンスに対して割り当て超過を行うことができますが、これは一定量の管理オーバーヘッドを意味します。これを行う唯一の有効な方法は、カスタム メモリ割り当て呼び出しを使用することです。クラス定義を変更せずに、これを行うことができます。

void* pMem = ::operator new(sizeof(myDerivedStruct) + n);
myDerivedStruct* pObject = new (pMem) myDerivedStruct;

operator delete階層内でオーバーロードしないと仮定すると、delete pObjectpObject を破棄して割り当てられたメモリの割り当てを解除する正しい方法になります。もちろん、余分なメモリ領域にオブジェクトを割り当てた場合は、メモリの割り当てを解除する前に、オブジェクトを正しく解放する必要があります。

nその後、次のアドレスで raw メモリのバイトにアクセスできます: void* p = pObject + 1. memcpy好きなようにこのエリアとの間でデータをやり取りできます。memcpyオブジェクト自体に割り当てることができ、そのデータに割り当てる必要はありません。

クラス自体にカスタム メモリ アロケータを提供することもできます。このアロケータには、余分size_tなメモリの量を記述する余分な記述が必要です。これにより、単一の式で割り当てを行うことができますnewが、これにはクラス設計でより多くのオーバーヘッドが必要になります。

myDerivedStruct* pObject = new (n) myDerivedStruct;

struct myDerivedStruct
{
    // ...
    void* operator new(std::size_t objsize, std::size_t excess storage);

    // other operator new and delete overrides to make sure that you have no memory leaks
};
于 2009-12-17T07:40:09.553 に答える
1

次のようにして、スペースを動的に割り当てることができます。

myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(new char[size]);

でも

これを実行してもよろしいですか?

また、文字列の先頭へのポインターとして ident を使用する場合は、正しくないことに注意してください。ident 変数自体が未使用スペースの先頭にあるため、実際には &ident が必要です。そのスペースにあるものをポインターとして解釈することはおそらく無意味です。したがって、 ident がではなくunsigned charまたはである方が理にかなっています。charunsigned char*

[もう一度編集] あなたがやっていることは本当に本当に悪い考えであることを強調したいと思います。

于 2009-12-16T22:57:45.077 に答える
1

この文脈では、ミキシングはひどいアイデアのようmemcpyに思えます。代わりにnew使用することを検討してください。malloc

于 2009-12-16T22:57:47.603 に答える
1

mallocで任意のサイズを割り当てることができます:

myDerivedStruct* pNewStruct = (myDerivedStruct*) malloc(
      sizeof(myDerivedStruct) + sizeof_extra data);

ただし、 myDerivedStruct::ident は非常にあいまいな構造であるという点で、別の問題があります。それはchar(配列)へのポインタであり、構造体はchar配列が始まるアドレスで終わりますか?ident はどこでも指すことができ、ident が指す配列の所有者が非常に曖昧です。構造体が実際の char 配列自体で終了し、構造体が余分な配列を所有していると思われるようです。このような構造体には通常、独自のサイズを追跡するためのサイズ メンバーがあり、API 関数がそれらを適切に管理してコピーできるようにします。余分なデータは慣例により、構造体の終了後に開始されます。char ident[0]または、一部のコンパイラで問題が発生しますが、長さ 0 の配列で終了します。多くの理由から、そのような構造体には継承の場所がありません。

struct myStruct 
{
size_t size;    
int a, b, c, d;    
char ident[0];
};
于 2009-12-16T23:10:56.913 に答える
0

まず、拠点を持つ意味がわからないmyBaseStruct。あなたは説明をしませんでした。

次に、元の投稿で宣言した内容は、説明したデータ レイアウトでは機能しません。OPで説明したことについては、構造体の最後のメンバーをポインターではなく配列にする必要があります

struct myDerivedStruct : public myBaseStruct {
    int a, b, c, d;
    unsigned char ident[1];
};

配列のサイズは問題ではありませんが、0 よりも大きくする必要があります。サイズ 0 の配列は、C++ では明示的に不正です。

第三に、何らかの理由でnew具体的に使用したい場合は、必要なサイズのオブジェクトのバッファーを割り当ててからchar、結果のポインターをポインター型に変換する必要があります

char *raw_buffer = new char[29];
myDerivedStruct* pNewStruct = reinterpret_cast<myDerivedStruct*>(raw_buffer);

その後memcpy、サイズが正しいと仮定して、 を実行できます。

于 2009-12-16T23:20:44.243 に答える
0
char* buffer = [some data here];
myDerivedStruct* pNewStruct = new myDerivedStruct();
memcpy(buffer,pNewStruct,4*sizeof(int));
pNewStruct->ident = new char[ strlen(buffer+(4*sizeof int)) ];
strcpy(pNewStruct->ident,buffer+(4*sizeof int));

そんな感じ。

于 2009-12-16T22:58:47.437 に答える
0

コンパイル時にバッファサイズはわかっていますか? その場合、静的に割り当てられた配列がより簡単な解決策になります。それ以外の場合は、上記の Remus Rusanu の回答を参照してください。これが、win32 API が可変サイズの構造体を管理する方法です。

struct myDerivedStruct : public myBaseStruct
{
    int a, b, c, d;
    unsigned char ident[BUFFER_SIZE];
};
于 2009-12-16T23:15:51.770 に答える