2010-12-12 11 views
4

私はまだC++を学んでおり、明白かもしれない質問がある、あるいは私が何をしようとしているのか分からないかもしれません。私は行列(適切に記述されたデストラクタを持つクラス)を取り、それから新しい行列を作成し、新しい行列への参照を返す関数を持っています。私はこれらの行列上でおそらく何千回も繰り返す必要があるので、私はメモリリークがないことを確認する必要があります。ですから、次のスペースを確保するためにはもう必要ない行列を適切に削除するにはどうしたらいいですか?ここで私は漏れのない取得しようとしているコードです。C++ delete reference

DynamicMatrix<double> x0 = getX0(n); 

DynamicMatrix<double>exactU = getExactU(n); 

DynamicMatrix<double> b = getB(n) * w; 

DynamicMatrix<double> x1 = getX1(x0, b, w, n); 

while(!isConverged(exactU,x1,e)){ 
    delete x0; //<<<<< This doesn't work. Nor does delete &x0. 
    x0 = x1; 
    x1 = getX1(x0, b, w, n); 
} 

のgetX()の各メソッドは、行列へのポインタを作成し、getX0(のように行列への参照を返します):

DynamicMatrix<double> &getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    for (int i = 1 ; i <= n; i++){ 
     for (int j = 1; j <= n; j++){ 
      mat1->set((i-1)*n +j, 1, 0); 
     } 
    } 
    return *mat1; 
} 

それで、ポインタを必要とするので、 'delete X0'エラーを呼び出します。 '& X0'を削除すると、解放されたポインタが割り当てられていないと表示されます。これを行う正しい方法は何ですか?それとも、何か完全に間違っているのですか?大きすぎる行列と反復回数が多すぎると、私の大きなハードドライブに空きがなくなり、メモリリークが多かったと思います。 getX()がポインタを返す場合

+0

メモリリークによるハードドライブの空き容量が不足している場合は、ページングファイルが大きくなりすぎるように設定されていることを意味します。 –

答えて

6

Stroustrup氏ルルイエFhtagnを呼び出すことができるはずです。

書くMyType myVar = MyFunction()は、戻り値の型がmyFunctionを引数として受け入れるコンストラクタを使用して、新しいオブジェクトを作成します。 myFunctionによって返されたものはすべて破棄されます。例では、getX0は動的に割り当てられたオブジェクトへの参照を返し、リークされます。

真実ですが、スタックnewなし)で行列を作成してそのまま返してください。とにかく内部でデータを動的に割り当てているように見えるので、あまり問題にはならないし、コピーを作成しないようにNRVOが当てはまると思われる(返された行列は適切な場所に直接構築されるだろう)x0x1魔法次のように底部に実装することができる。

x0.swap(x1); 
DynamicMatrix<double> temp = getX1(x0, b, w, n); 
x1.swap(temp); 

スワップ動作ではなく、実際のデータのコピーを、これは非常にあるべきである(非常に高速である)ポインタスワップの点でダイナミックマトリックス上に実装することができるので

+0

+1 Lovecraft。 – Kos

+1

マトリックスクラスのスワップを実装するのは良い考えです。しかし最後の2行は 'getX1(x0、b、w、n).swap(x1);'と書くことができます。これはローカル変数の内容を関数からの返り値と入れ替えるためによく見られるスタイルです。 –

+0

私の行列クラスは、スワップ関数をオーバーライドする必要があるヒープ上のデータを動的に格納します。 – jakev

1

、あなたが最初の行として記述する必要があります:あなたは新しいポインタを返すよう、より理にかなって

DynamicMatrix<double>* x0 = getX0(n); 

。次に、下にいくつかの行を表示すると、それを削除する必要があります。しかし、あなたがboost::shared_ptrを使用してトラブルを大幅に節約できること

注:

typedef boost::shared_ptr<DynamicMatrix<double> > dyn_matrix_ptr; 

dyn_matrix_ptr x0 (getX0(n)); 
// use x0 as a normal pointer 
... 
// You don't have to manually delete it, it will be deleted automatically. 
2

あなたは、ポインタを使用する必要があります。ステートメント

DynamicMatrix<double> x0 = getX0(n); 

マトリックスのコピーを作成します。

DynamicMatrix<double> x0 = getX0(n); 

あなたは、ポインタを使用する必要があり、必ずしもいけない:あなたはあなたのバグはここにある

DynamicMatrix<double> *getX0(int n){ 
    DynamicMatrix<double>* mat1 = new DynamicMatrix<double>(n * n,1); 
    ... 
    return mat1; 
} 

その後

DynamicMatrix<double> *x0 = getX0(n); 
... 
delete x0; 
+0

でも、x0 = x1とすると、それぞれが別のコピーを指し示すようになります。 – jakev

+0

@JakeVA: 'delete x0; x0 =新しいDynamicMatrix (x1); ' –

+0

@ JakeVA:しかし、あなたはコピーを望んでいません、あなたは所有権を引き継ぐ必要があります。 –

0

をしたいです。新しいオブジェクトへの参照を返すことができます。メモリを削除するには、参照のアドレスを取得します。参照のアドレスを指定すると、参照先のアドレスが与えられます。あなたは

// receive newed memory in a reference 
DynamicMatrix<double>& x0 = getX0(n); 

// &x0 should give you the address of the allocated memory. 
delete &x0; 
0

DynamicMatrix<double>のルールは、基本的にはintと同じです。

「auto」変数としてスタックに割り当てられていた場合は、それをクリーンアップする正しい方法は何もしないことです。範囲外にするだけです。このようにできるだけコードを整理したいと考えています。

「new」で割り当てられていた場合は、「delete」でクリーンアップしてください。

何かを動的に割り当ててから参照してください。ポインタを返します。実際には、そうしないでください。スマートポインタクラスを使用します。お願いします。

必要がない場合は、動的に割り当てないでください。局所的な値を作り、それを返します。でを返します(非静的なローカルへの参照を返すことはできません)。 は次のようなコードを書いていると思いますか?

int& give_me_a_value() { 
    int* result = new int(rand()); 
    return *result; 
} 

は再び:DynamicMatrix<double>のルールは基本的に、彼らはintのためのものと同じです。そのため、コピーコンストラクタ、代入演算子、デストラクタを実装しています。これは実際にあなたが期待する方法で実際に動作するようになっています。

+0

あなたが与えた例..私はまだ参照とポインタの違いを整理し、それらの間の変換を試みています。率直に言って、私はそのようなコードを書くかもしれません。それが私の行列クラスでやったことです。それが正しいと思いました。私は参照を返すことでどのようにコピーを作成するのが直感的ではないと思います。 – jakev

+0

さて、このコードを見てみましょう: 'int give_me_a_value(){int result = rand();結果を返す; 'それほど多くの雑誌を見ない、まあ、**通常**?私は本当に、本当にそれが願っている、そうでなければあなたは非常に、**非常に**奇妙な参照資料から学んできました。参照を返す**はコピーを作成しません - それがポイントです。 **値で**返す。 –

+0

一般に、ある関数が何かへの参照を返すとき、その関数が**呼び出されたときにすでに存在していた**への参照を返すはずです。 –