2009-03-25 19 views
2

以下、私はではありません。を指針としてmy_intsと宣言しています。私はメモリがどこに割り当てられるのか分からない。ここに私を教えてください!これら2つのクラスの違いは何ですか?

#include <iostream> 
#include <vector> 

class FieldStorage 
{ 
private: 
    std::vector<int> my_ints; 

public: 
    FieldStorage() 
    { 
     my_ints.push_back(1); 
     my_ints.push_back(2); 
    } 

    void displayAll() 
    { 
     for (int i = 0; i < my_ints.size(); i++) 
     { 
      std::cout << my_ints[i] << std::endl; 
     } 
    } 
}; 

そしてここで、私はポインタとしてフィールドmy_intsを宣言している:テストへ

#include <iostream> 
#include <vector> 

class FieldStorage 
{ 
private: 
    std::vector<int> *my_ints; 

public: 
    FieldStorage() 
    { 
     my_ints = new std::vector<int>(); 
     my_ints->push_back(1); 
     my_ints->push_back(2); 
    } 

    void displayAll() 
    { 
     for (int i = 0; i < my_ints->size(); i++) 
     { 
      std::cout << (*my_ints)[i] << std::endl; 
     } 
    } 

    ~FieldStorage() 
    { 
     delete my_ints; 
    } 
}; 

main()は機能:

int main() 
{ 
    FieldStorage obj; 
    obj.displayAll(); 
    return 0; 
} 

それらの両方が同じ結果を生成します。違いは何ですか?

+0

メモリリークを指摘してくれた皆様、ありがとうございました。 – Srikanth

答えて

13

メモリ管理に関して、これらの2つのクラスは事実上同一です。他のいくつかのレスポンダーは、スタックとヒープ上にストレージを割り当てるという点で2つの違いがあることを示唆していますが、必ずしもそうではなく、真実であっても誤解を招くことがあります。実際には、違いはvectorメタデータが割り当てられる場所です。 vectorの実際の基礎となるストレージは、ヒープに関係なく割り当てられます。

std::vectorを使用しているため、これを確認するのはちょっと難しいので、具体的な実装の詳細は隠されています。 - 容量、サイズと実際を格納するメモリの動的に割り当てられたブロックへのポインタ

template <class T> 
class vector { 
public: 
    vector() : mCapacity(0), mSize(0), mData(0) { } 
    ~vector() { if (mData) delete[] mData; } 
    ... 
protected: 
    int mCapacity; 
    int mSize; 
    T *mData; 
}; 

あなたが見ることができるように、vectorクラス自体はほんの数メンバーがあります。しかし、基本的には、std::vectorは、このように実装されますベクトルの内容

この例では、唯一の違いは、そのような少数のフィールドのストレージがどこから来るかです。最初の例では、格納先のクラスに使用するストレージから割り当てられます。ヒープが割り当てられている場合は、vectorのビット数も少なくなります。コンテナにスタックが割り当てられている場合は、vectorのビット数も少なくなります。

第2の例では、vectorのビットは常にヒープ割り当てされています。

両方の例では、実際のvectorの肉(その内容)はヒープから割り当てられており、変更することはできません。

他の誰もが、2番目の例ではメモリリークが発生していることを既に指摘しており、それも当てはまります。コンテナクラスのデストラクタ内のベクターを削除してください。

+0

実際には、最初のケースではベクトルオブジェクトがスタックに割り当てられます。ヒープ上にメモリを内部的に割り当てるという事実は、この事実とは関係ありません。 –

+0

... "この特定のサンプルコードの違いは何か"ではなく、非ポインタメンバーです。もちろん、サンプルコードは絶対に正しいですし、それが意味するものなら、私はお詫び申し上げます。 :-) – Dan

+0

@ネマンジャー:私は私の答えでそれに取り組んだと思うし、ダンはすでに私の意見を明確にした。とにかく、最も重要なことは、メモリ使用量の大部分がどこから来ているかです。これはメタデータではなくベクトルの内容であり、内容は常にヒープに割り当てられます。 –

4

FieldStorageデストラクタの2番目のケースでベクターに割り当てられたメモリを解放する必要があります(メモリリークを防ぐため)。

FieldStorage::~FieldStorage() 
{ 
    delete my_ints; 
} 
+0

+1。あるいは、std :: auto_ptr、boost :: scoped_ptr、boost :: shared_ptrなどのスマートポインタを使用する方がよいでしょう。いずれにしても、コピーコンストラクタとコピーの割り当てを考慮する必要があります。コンパイラ提供のデフォルトでは不十分です。 –

+0

本当にこれが必要かどうかは分かりません。私が正しく覚えていれば、デフォルトのデストラクタがクラスのフィールドのすべてのデストラクタを呼び出すというEffective C++を読みました。それは本当ですか、私は理解していますか? – Srikanth

+0

これは最初のケースで機能します。 2番目のケースでは、クラスのデストラクタはポインタ自体によって獲得されたメモリを解放しますが、newによって割り当てられたメモリは解放しません。 my_intsがFieldStorageより長持ちしない限り、最初のケースを使用してください。 –

1

最初の方法は、使用するのが好ましい方法です。ベクター上にポインタを置く必要はなく、削除することを忘れてしまっています。

+0

私は「正しい」よりも「好まれる」と言います。 –

+0

私は、指摘された場合にクラスのメンバーとして "ベクトル*"を使用する理由は何も見ません。そう、「正しい」はあなたがどうすべきかを反映しています。それは "間違っている"ことができ、まだ仕事をしています。 –

2

最初の例では、オブジェクトはスタックに割り当てられています。

第2の例では、オブジェクトはヒープに割り当てられ、そのメモリへのポインタがスタックに格納されます。

+0

使用状況が「FieldStorage obj = new FieldStoreage();」の場合どのようにあなたの答えに影響を与えますか?すべてのプリミティブがスタックに割り当てられていますか? ctorのベクトルに追加されたものはどうですか?それらはスタックにありますか? –

+0

@BinaryWorrier: "FieldStorage obj =新しいFieldStorage();"ナンセンスです。 "新しいFieldStorage()"の戻り値の型は 'FieldStorage *'です。あなたの他の質問については、私は知らない。私がC++を使用して以来、しばらくしてきました。 – Welbog

+0

ヒープにFieldStorageを割り当てると、ベクトルはそのヒープ割り当ての一部を使用します。スタックにFieldStorageを割り当てると、ベクトルはそのスタック割り当ての一部を使用します。グローバルなFieldStorage ...をうまく定義すると、画像が得られます。 – bk1e

3

Mykola Golubyevが指摘したように、2番目のケースではベクターを削除する必要があります。

オプティマイザは、ベクトルを含むフルサイズのFieldStorageをが知っていて、両方のために十分なメモリを割り当てることができるため、高速なコードを作成する可能性があります。

2番目の実装では、オブジェクトを構築するために2つの別々の割り当てが必要です。

1

違いは、2番目のベクトルがベクトルを動的に割り当てることです。いくつかの違いがあります。

  • あなたが(それは、ベクターによって正しく処理されるため、ベクトルオブジェクト自体ではなく、ベクトルに保管オブジェクト)ベクトルオブジェクトによって占有されていたメモリを解放する必要があります。いくつかのスマートポインタを使用してベクトルを保持するか、(たとえばデストラクタで)makeする必要があります。

    delete my_ints;

  • オブジェクトがスタックに割り当てられているため、最初の方が効率的です。ベクトルの方法に

  • アクセス異なる構文を持っている:)

0

最初のケースでは、STD ::ベクトルは、あなたのクラスに直接置かれている(そしてそれは、メモリの割り当てを処理し、それを割当てを解除されますあなたのオブジェクトが破壊されたときにベクトルを拡大縮小する必要があり、それを処理する必要がないようにメモリ管理を抽象化しています。 2番目のケースでは、ヒープ内のstd :: vector用の記憶域を明示的に割り当てて、削除することを忘れてしまい、プログラムがメモリをリークします。

+0

"、それはベクトルの拡大と縮小に必要なメモリ割り当てと割り当て解除を処理しています。" 。 。どちらの場合も起こります。 –

3

私はあなたが本当にStack and the Heapの違いを探していると思います。

最初のスタックはスタックに割り当てられ、2番目のスタックはヒープに割り当てられます。

+0

「スタック上のメンバー」の正しい名前は何ですか?それは奇妙に聞こえる。オブジェクトのインスタンスがどのように割り当てられるのかわからない場合、どうやって「スタック」することができますか? –

+0

-1が正しくありません。最初のケースでは、my_intsはオブジェクトの一部として割り当てられます。スタック上にあるかヒープ上にあるかは、インスタンス自体の割り当て方法によって異なります。 2番目のケースでは、それは別のヒープ割り当てです。 –

+0

フレッド、私はあなたが正しいと思います。それは意味をなさないでしょう。ありがとう。 –

1

最初のバージョンのFieldStorageにはベクターが含まれています。 FieldStorageクラスのサイズには、ベクトルを保持するのに十分なバイト数が含まれます。 FieldStorageを構築すると、VectorはFieldStorageのコンストラクタの本体が実行される直前に構築されます。 FieldStorageが破棄されると、ベクトルも破棄されます。

これは必ずしもベクトルをスタックに割り当てるわけではありません。 Heap-allocate FieldStorageオブジェクトの場合、ベクトルのスペースはスタックではなくヒープの割り当てになります。グローバルなFieldStorageオブジェクトを定義した場合、ベクトルのスペースはスタックやヒープからではなく、グローバルオブジェクト用に指定されたスペースから得られます(一部のプラットフォームでは.dataまたは.bssセクションなど)。

ベクトルは実際のデータを保持するためにヒープ割り当てを実行するので、ポインタやいくつかの長さのポインタしか含まれていない可能性がありますが、コンパイラのSTL実装が必要とするものを含んでいる可能性があります。

第2バージョンのFieldStorageには、ベクトルへのポインタが含まれています。 FieldStorageクラスのサイズには、実際のベクトルではなくベクトルへのポインタのための領域が含まれます。 FieldStorageのコンストラクタの本体でnewを使用してベクトルの格納領域を割り当てていて、ベクトルを削除するデストラクタを定義していないため、FieldStorageが破棄されたときにその格納領域が漏れてしまいます。

0

オブジェクトのサイズが異なるようになります。 2番目のケースでは、Vector <> *はポインタのサイズ(32ビットマシンでは4バイト)のみを占有します。最初のケースでは、オブジェクトは大きくなります。

0

実際の違いの1つは、2番目の例では、ベクトルまたはその内容(削除しないため、デストラクタを呼び出すため)のメモリを解放しないことです。

しかし、最初の例では、FieldStorageオブジェクトが破棄されると自動的にベクターが破棄され(その内容が解放されます)

関連する問題