1

new/mallocC/C++ では、関数が終了する前にメモリを使用する必要があるというのは常識のようdelete/freeですよね。

readerしかし、ファイルからチャンクをバッファに読み込む関数consumerがあり、これらのバッファを後で消費する別の関数があるというこの種の問題があるとします。

void reader(ifstream &ifs)
{
    char *buf = new char[100];
    ifs.read(buf, 100);
    save_buffer(buf);  //save this buf into a global array, say buf_array[10]
}

void consumer()
{
    for(int i = 0; i < 10; i++)
        consume( buf_array[i] );  //do something with those buffers read by reader
}

私の問題は、多くのメモリ リソースが内でnew編集されていますが、これらのバッファが で使用されていないため、編集できないことです。それらのバッファを処理する必要がありますか?readerreaderdeleteconsumerconsumerdelete

4

9 に答える 9

4

メモリを割り当てる関数がメモリを解放する必要があるとは誰も言いませんでした。ただし、通常は同じコンポーネントで処理する必要があります。あなたreaderとあなたconsumerはペアを組んでいるので、一緒に思い出をコーディネートしても大丈夫です。

于 2012-07-26T02:36:53.107 に答える
1

他の人とは少し異なる答え:

はい、リーダーが読み取り機能でメモリを解放/削除しないことは問題ありませんが、消費者にメモリを削除させることはありません。単純なケースでは機能しますが、複数のコンシューマーがある場合 (たとえば、異なる形式で出力する場合) はどうでしょうか? データを消費すると解放されるという副作用がある場合、最初のコンシューマが処理を行った後は、そのデータに対して他に何もできなくなります。

必要にcleanup()応じてバッファをクリーンアップするために明示的に呼び出す型メソッドをリーダーに用意します。このように、メモリを割り当てるモジュールは、(別の方法であっても) メモリを解放する責任があります。

例えば

Data d = Reader.read();
Consumer1.consume(d);
Consumer2.consume(d);
Reader.cleanup(d);
// d is no longer valid.
于 2012-07-26T02:47:18.373 に答える
1

buf の内容を、実際に消費者に供給するグローバル配列 buf_array にコピーしています。したがって、上記の例では、リーダーは buf を解放できます。

また、new/mallocs 関数がメモリを解放する必要はありません。ポインターを渡すことができます。割り当てられたメモリを最後に使用する関数は、メモリを解放する必要があります。

于 2012-07-26T02:47:29.753 に答える
1

new/mallocC/C++ では、関数が終了する前にメモリを使用する必要があるというのは常識のようdelete/freeですよね。

いいえ、これは必ずしも真実ではありません。プログラムが終了する前に最終的にメモリを解放する限り、同じ関数でメモリを解放する必要はありません。

C++ で利用できる (ただし C では利用できない) 一般的な解決策の 1 つは、デストラクタでメモリの割り当てを解除することです。コピー/移動コンストラクターと代入演算子を正しく処理しながら、動的に割り当てられたメモリを含むオブジェクトを渡すと、デストラクタが呼び出されたときにメモリが解放されます。

于 2012-07-26T02:37:16.907 に答える
1

原則は、「すべての に対してnew、あるべきdelete」です。これは、両方の呼び出しが同じ関数内になければならないことについては何も言いません (明らかに、それはあまり役に立ちません)。

リーダーの割り当てと消費者の解放の例に問題はありません。

于 2012-07-26T02:37:34.420 に答える
1

new/malloc同じ関数で(割り当て) とdelete/free(解放)を行う必要はありません。メモリ リークが発生しないように、すべての割り当てが解放され、一度だけ解放されることがアルゴリズムによって保証されている限り、問題はありません。
実際、多くの場合、割り当てと解放は別々の関数に存在します。
これらを覚えておいてください:
1. 同じポインターを使用してリリースを行います (もちろん、ポインターを渡すことができます)。ポインターに対して何らかの演算を行ってから、その変更されたポインターを使用して割り当てを解放すると、ポインターがまだ割り当て領域を指していてもエラーが発生します。
2. 前述のように、割り当てが解放されたことを 1 回だけ保証する必要があります。追加リリースはエラーになります。

于 2012-07-26T02:38:33.607 に答える
1

バッファへのポインタを保持している限り、割り当てられたバッファを初期化した同じ関数で解放する必要はありません。

あなたの場合、によって割り当てられたバッファconsumer()を処理する必要があります。deleteconsumer

2番目の質問については、消費者はバッファがどこで終了するかを知りません。なんとなく伝える必要があります。バッファーへのポインターを格納するだけでなく、バstruct​​ッファーとその長さの両方をカプセル化する新しい定義を検討することもできます。これはすでに行われています: using を見ることを検討してstd::stringください。

于 2012-07-26T02:39:10.333 に答える
0

共有アレイについても読むことができますhttp://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/shared_array.htm

共有配列を使用すると、それらを関数内に割り当て、値で他の関数に渡すことができます。共有配列は、参照された回数の内部カウントを保持し、すべての参照がスコープ外になると自動的にメモリを削除します。

例えば

void bar( boost::shared_array< int > );

void foo()
{
    boost::shared_array< int > x ( new int[ 100 ] );
    bar( x );
    // because x has been passed to bar(), its reference count is incremented
    // and it will not only be deleted when everyone is finished with it!

    // do more things with x
} // the memory held by x is deleted

void bar( boost::shared_array< int > y )
{
    // Do things with y here
} // the memory held by y is not deleted here because foo() hasn't yet finished
于 2012-07-26T03:29:02.760 に答える
0

優先度の高い順に並べると、次のようになります。

  1. ストレージ クラスを使用するautoと、削除が自動的に行われます。
  2. 同じコードでオブジェクトの割り当てと削除を行います。
  3. 所有権を渡すので、1 つのコンポーネントが割り当てられ、別のコンポーネントが解放されます。
  4. のようなものを介して所有権を共有していshared_ptrます。

3 と 4 はほぼ同点ですが、どちらも 2 に大きく遅れをとっており、1 に大きく遅れをとっています。

この場合、プロデューサーとコンシューマーの両方の上にある関数 (またはクラスなど) のレベルで、バッファーを割り当て、プロデューサーとコンシューマーを開始し、両方が終了したらバッファーを削除することをお勧めします。

class buffer { 
     std::vector<char> data;
public:
     buffer() : data(100) {}
};

process_file(std::string const &name) { 
    std::vector<buffer> buffers(10);

    std::ifstream in(name);

    std::pair<std::ifstream *, std::vector<buffer> *> thread_data = {
        &in, &buffers
    };

    prod = start_thread(producer, (void *)&thread_data);
    cons = start_thread(consumer);
    join(prod);
    join(cons);
}

これができれば、メモリを管理する際の多くの頭痛の種を回避するのに役立ちます。

于 2012-07-26T03:49:06.967 に答える