2

ベクトルへのポインターのベクトルがあります。

main(...)
{
  //...
  std::vector< std::vector<double> * > ds = getDS(...)
  //...
}

std::vector<std::vector<double> * > getDS(int m, ...)
{
  std::vector<std::vector<double> * > wavefunctions = *(new std::vector<std::vector<double>*>(m));
  int n = int( params.rmax() / params.dr() );
  std::ifstream input_wf;
  input_wf.open(filename.c_str());
  input_wf.setf(std::ios::showpoint | std::ios::scientific);
  for(int i=0; i < nbasis; i++)
  {
    std::vector<double> *wf = new std::vector<double>(n);
    //(wavefunctions[i]) = new std::vector<double>(n);
    for (unsigned int ir=0; ir < wf->size(); ir++)
      input_wf >> ( *wf )[ir];
    wavefunctions.push_back(wf);
  }
  input_wf.close();
  return wave functions;
}

wavefunctions[0]->at(some legal value)しかし、デバッグ中に一度ループを抜けてアクセスしようとすると、EXC_BAD_ACCESSエラーが発生し続けます。(そこに何かがあるはずですが、なぜないのかわかりません...何かアイデアはありますか?

4

4 に答える 4

2

次の行、

  std::vector<std::vector<double> * > wavefunctions = *(new std::vector<std::vector<double>*>(m));

あなたの場合、2つの理由で問題があります-

  1. newによって作成されたオブジェクトが にコピーされ、そのオブジェクトwavefunctionsへのポインタが失われるため、メモリ リークが発生します。これはJavaではありません...
  2. mベクトルにエントリを割り当てます。Subsequentはそのエントリにpush_back追加されるため、実際にアクセスしようとすると、ループで最初にプッシュされるエントリではなく、この行で作成されたエントリにアクセスします。mwavefunctions[0]for

この問題を解決するには、行を次のように変更します。

std::vector<std::vector<double> * > wavefunctions;
wavefunctions.reserve(m);

このreserve方法により、push_backの実行中に再割り当てが発生しないことが保証されます。

最後に、状況に応じて、コンパイラは、関数からの戻り時に実行されるベクトルの固有のコピーを最適化できる場合とできない場合があります。確かに、右辺値参照 ( &&) についてさらに学習するか、単純にベクトルをアドレスで (つまり、型vector<...> *と戻り値の型の別のパラメーターとしてvoid) 返すことをお勧めします。

于 2012-07-16T22:41:26.287 に答える
1

コードは私にはうまくいくように見えますが、動的割り当てが多すぎます。(戻り値をタイプミスしましたが。) user1071136 がバグを発見しました。

ほとんどの場合、 は入力deleteしないでくださいnew。コンストラクターでストリームを開くこともでき、ストリームはそれ自体を閉じます。これを行う必要はありません。また、ストリームの状態をチェックして、値が読み込まれているかどうかを確認するのも忘れていました。

std::vector<std::vector<double>> getDS(int m, ...)
{
  std::ifstream input_wf(filename.c_str());
  input_wf.setf(std::ios::showpoint | std::ios::scientific);

  int n = int( params.rmax() / params.dr() );
  std::vector<std::vector<double>> wavefunctions(m, std::vector<double>(n));
  //m by n vector is fully constructed, and ready to read!
  for(int i=0; input_wf && i<nbasis; i++)
  {
    for (unsigned int ir=0; input_wf  && ir<wf->size(); ir++)
      input_wf >> wavefunctions[i][ir];
  }
  if (!input_wf)
      throw std::runtime_error("improper data in the file!");
  return wavefunctions;
}
于 2012-07-16T22:47:37.057 に答える
0
std::vector<std::vector<double> * > wavefunctions = *(new std::vector<std::vector<double>*>(m));

これは私には疑わしいように見えます。私はあなたが2つのことのうちの1つをしているつもりだと信じています。

これをスタックで宣言し、そのコピーを返します。

 std::vector<std::vector<double> * > wavefunctions;

ヒープで宣言し、関数からポインターを返します。(これにより、呼び出し元は割り当てられたメモリを削除する責任を負います。)

std::vector<std::vector<double> * > *wavefunctions = new std::vector<std::vector<double>*>(m);
于 2012-07-16T22:41:47.000 に答える
0

まず、なぜポインタのベクトルを維持しているのでしょうか? これを行う正当な理由はほとんどありません (理由は思い浮かびませんが、すべてを知っているわけではありません)。ポインターを格納する必要がある場合は、スマート ポインターを格納します。ベクターがメモリを管理する能力を否定しています。

std::vector<std::vector<double> * > wavefunctions = *(new std::vector<std::vector<double>*>(m));

ここでnewベクトルを作成し、すぐに逆参照してローカル ベクトルにコピーします。'd ベクトル (およびそのポインタ) が失われるため、メモリ リークが発生しnewます。単にコピーを作成して破棄しただけです。繰り返しますが、ポインターをベクトルに格納するのは悪い考えであり、割り当て方法は常に間違っています。

a を使用してvector<vector<double> >、ベクトルに動的メモリを管理させるだけです (ただし、コードが何を行っているかを理解するために、このテーマについてもう少し勉強することをお勧めします)。

これを言うのは少し躊躇しますが、ベクターを使用してギザギザ配列をエミュレートすると、パフォーマンスの問題が発生する可能性があります。問題はデータのローカリティの 1 つですが、これはパフォーマンスに敏感なコードのタイトなループでのみ適用され、ポイントを無意味にする可能性のある多くの要因があります。

于 2012-07-16T23:25:06.177 に答える