2013-07-23 15 views

答えて

9

悲しいことに、あなたはできません。スコット・メイヤーの本の中には、これを達成しようとするときの課題について説明している部分がありますが、それは不可能です。

より効果的なC++ - Item#27:ヒープベースのオブジェクトの必要性または禁止。

[OK]を、ここで簡単に実証されている問題の一つです(ここで問題になっている項目は複数のページが長いので、私はそれのすべてを要約しませんですが、だ少なくとも一つの挑戦):

多くの(すべてではありません)システムは、以下の方法で自分のメモリを手配:

---------------- 
|  Stack | 
| (Grows Down) | 
|    | 
---------------- 
|    | 
|    | 
|    | 
|    | 
|    | 
|    | 
---------------- 
|  Heap  | 
| (Grows Up) | 
|    | 
---------------- 

今、あなたはあなたがヒープか右にしているかどうかを把握するオペレータ新しい/ new演算子と巧妙な何かを行うことができ、このようなメモリ配置に思うかもしれません(あなたが特定のメモリ位置の上か下かをチェックすることによって)?ここに問題がある。静的オブジェクトが移動する場所はシステムによって異なりますので、次のようになります。

---------------- 
|  Stack | 
| (Grows Down) | 
|    | 
---------------- 
|    | 
|    | 
|    | 
|    | 
|    | 
|    | 
---------------- 
|  Heap  | 
| (Grows Up) | 
|    | 
---------------- 
| Static | 
| Objects | 
---------------- 

これで、静的オブジェクトとヒープオブジェクトを区別できなくなりました。おっとっと!また、私はこれがシステムに依存していると言いました。つまり、それらを区別する方法を見つけたとしても、あなたのコードは移植性がありません。

+2

難易度についてさらに教えてもらえますか? – hivert

+0

私はそれらを今見ています。私は心からそれらを知らない。 – Borgleader

+4

@hivert:基本的な難しさは、言語によってオブジェクトがどのように割り当てられたかを伝えることができないということです。あなたは、スマートポインタまたは "operator new/delete"のオーバーロードを使って動的オブジェクトを追跡することができます。静的、自動、スレッドローカルおよび一時オブジェクトを区別する方法はありません。 –

2

警告:これは以下に説明するように、「未定義の動作」を使用しています - MOSTプラットフォームで動作することが知られています(Windows、Linux、Symbian OSではARMおよびx86で十分です。 「フラット」メモリモデルを使用するほとんどのOSで)。

自分自身を特定のシステムに「限定」すると、thisと「スタックがある場所」(そして必要な場合は静的データがある場所)の既知の範囲を比較することができます。 [スタックが任意のスレッドのどこにあるのか把握することは可能ですが、少し難しくなります]。静的データの知識を用いて

、およびスタックが配置されている、我々はスタックがどこにあるか、あなたが実際に何とか把握できる場合にのみ動作すること

char *this_addr = static_cast<char*>(this); 
if (this_addr >= globa_start && this_addr <= global_end) 
    globals++; 
else if (this_addr >= stacK_top && this_addr >= stack_base) 
    stacked++; 
else heaped++; 

注比較することができます - そしてもちろん、それはだが定義されていない振る舞いを持っているため、thisは割り当てられたブロックの外のものと比較されるので、技術的には全体の概念は未定義です。しかし、これはほとんどのOS /プロセッサー・アーキテクチャーで可能です。 [もちろん、デストラクタでも同じことをする必要がありますが、逆にする必要があります]。また、オブジェクトを作成したスレッドとは別のスレッドからオブジェクトを破棄すると、 "楽しい"状態になります)。

編集:与えられたスレッドのスタックを見つけることはそれほど難しくありません。複数のスレッドが存在する]] "最初の関数"(スレッド作成呼び出しに渡されたもの)のローカル変数のアドレス。次に、現在のスレッドの変数のアドレスを取得します。これらの値の間にあるものは、そのスレッドスタックにあります。スタックは連続した1つのメモリの一塊であるためです。

+0

好奇心のために、64ビットで動作するでしょうか(charにキャストしても問題ありません)? –

+0

これは 'char *'であることを意味していました。 –

0

アクティブなオブジェクトの数を追跡するための最も簡単な解決策は、トレースしたいクラスで

(のgetSize()関数または任意で)オブジェクトマネージャを作成することで、あなたはまた、静的プロパティを追加することができましたコンストラクタとデストラクタでそれぞれ増減します。あなたが個別にこれらの数字を取得することができるようになりますオブジェクトマネージャ(動的割り当て)の大きさと静的プロパティ(すべての割り当て)

。オプションとして

+0

OPは、動的に割り当てられたオブジェクトと静的に割り当てられたオブジェクトを区別したいと考えています。 – Borgleader

+0

動的割り当ての数とすべての割り当てで、静的割り当ての数を簡単に計算できます。 これは素晴らしいシステムではありませんが、それは私が現時点で考えることができる最も簡単なものです:) – Rak

0

は、あなたが世界的に新しい過負荷および/デクリメント動的に割り当てられたオブジェクトのグローバルカウントを与えるいくつかの静的なカウンタをインクリメントする削除することができます...

+0

全体の難しさは、静的と動的割り当てを区別することです。どのようにすればいいのか説明してください。 – Borgleader

+0

はい、私はまだ答えはありません...ちょうどカウント(および適切な過負荷の各オブジェクトのサイズ)を取得する方法を説明するために過負荷の可能性を言及したかっただけでなく、これもシステムに依存しないでください。 –

+0

@Borgleaderここでは、これが許容可能な解決策ではないというヒントはありません。また、他の人が指摘しているように、未定義の動作を引き起こさずにこれを行う方法はありません。さらに、メモリリークや何かを解決しようとしているのでなければ、これを行う唯一の正しい解決策だと思います。その場合はvalgrindのような適切なツールを使用する必要があります。より詳細な解決策については私の答えをご覧ください。 – Fozi

0

あなたは、単にに関する引数を渡すことで、クラスを言うことができますその場所:

class LocationAware { 
public: 
    enum Location { STATIC, STACK, HEAP }; 
    explicit LocationAware(Location location) : my_location(location) { 
     switch(location) { 
      case STATIC: ++static_instaces; break; 
      case STACK: ++stack_instances; break; 
      case HEAP: ++heap_instances; break; 
     } 
    } 

    ~LocationAware() { 
     switch(my_location) { 
      case STATIC: --static_instaces; break; 
      case STACK: --stack_instances; break; 
      case HEAP: --heap_instances; break; 
     } 
    } 

private: 
    const Location my_location; 

public: 
    static unsigned static_instaces; 
    static unsigned heap_instances; 
    static unsigned stack_instances; 
}; 

unsigned LocationAware::static_instaces = 0; 
unsigned LocationAware::heap_instances = 0; 
unsigned LocationAware::stack_instances = 0; 

LocationAware stat(LocationAware::STATIC); 

int main() { 
    LocationAware stack(LocationAware::STACK); 

    LocationAware * heap = new LocationAware(LocationAware::HEAP); 
} 

もちろんこのクラスに嘘をつくことができます。しないでください。

また、テンプレートを作成して継承やカプセル化を使用し、クラスから使用することができます。

template<class Tag> 
LocationAware; 

次に、クラス内の場所を継承または保持して初期化します。インスタンスはLocationAware<YourClassOrTag>::xy_instancesを使用して確認できます。

関連する問題