2

ダミーリストだけを返すように単純化した単純な関数があります(論理エラーではないことを確認するため)

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    ...
    values.clear();
    values.push_back(2);
    values.push_back(3);
    cout << "values is of size " << values.size() << endl;
    return &values;
}

次に、cppunit テストで:

vector<AttrValue>* candidateList0 = evaluator->getCandidateList(cl, 0);
cout << candidateList0->size() << endl;

しかし、問題はsize()、テストでは、coutメッセージが正しいサイズ 2 を出力しているにもかかわらず、常に 0 であることです。何が間違っているのでしょうか?

簡単なプログラムを試してみましたが、問題ないようです...

#include <iostream>
#include <vector>
using namespace std;

vector<int>* test() {
    vector<int> vec { 2, 3, 6, 1, 2, 3 };
    return &vec;
}

int main() {
    cout << test()->size() << endl;
    return 0;
}
4

3 に答える 3

4

関数から一時的なアドレスを返してgetCandidateListいます。関数が戻ると、オブジェクトは解放されます。それへのアクセスは未定義の動作です。ベクトルを返すだけで、RVOがコピーを適用して除外する必要があります。

試す:

std::vector<AttrValue> QueryEvaluator::getCandidateList(...) 
{
  //blah
  return values; 
}

簡単なプログラムを試してみましたが、問題ないようです...

getCandidateList 関数が戻ると、一時的なベクトルが解放されます。プログラムには未定義の動作があります。

于 2013-01-25T11:00:25.297 に答える
2

ベクターはスタック上で宣言されているように見えるため、スコープ外になると (関数が終了すると) 破棄されます。ベクトルへのポインターを返したい場合は、代わりにヒープに割り当てます

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    vector<AttrValue>* values = new vector<AttrValue>();
    ...
    values->clear();
    values->push_back(2);
    values->push_back(3);
    cout << "values is of size " << values->size() << endl;
    return values;
}

代わりに、呼び出し元で宣言して参照を渡す方が簡単かもしれませんgetCandidateList

void QueryEvaluator::getCandidateList(vector<AttrValue>& values)

...または値で返す

vector<AttrValue> QueryEvaluator::getCandidateList(...) {
于 2013-01-25T11:00:05.400 に答える
1

考慮すべき非常に多くの興味深い事項:

vector<AttrValue>* QueryEvaluator::getCandidateList(...) {
    ...
    values.clear();
    values.push_back(2);
    values.push_back(3);
    cout << "values is of size " << values.size() << endl;
    return &values;
}

つまり、コードの中で最も興味深い部分を省略しているように見えます...上記。ストーリーの教訓は、エラーを示すコンパイル可能な作業コードを試して提供することです。問題を小さな例に縮小すると、通常、自分で問題を見つけることになります。少なくとも、使用されるすべてのオブジェクトの正確な定義を提供する必要があります (C++ では型が最も重要です)。

ベクトルをローカルオブジェクトとして宣言していますか?

 std::vector<int>  values;

この場合、ベクトルの寿命は関数にバインドされ、関数の最後で破棄されます。これは、関数が戻った後にそれを使用することは未定義の動作であることを意味します (何が起こる可能性があります)。

しかし、ユニット テスト フレームワークの一部としてオブジェクトを使用しているようにも見えます。したがって、可能性のある解決策は、ベクトルをオブジェクトの一部にすることです。次に、ベクトルはオブジェクト (関数呼び出しだけでなく) の間存続するため、オブジェクトへのポインターを返すことは期待どおりに機能します。

 class  QueryEvaluator
 {
     std::vector<int>   values;
     public:
         vector<AttrValue>* QueryEvaluator::getCandidateList(...);
 };

別の方法は、ポインターではなく値でベクトルを返すことです。これは、オブジェクトが関数から正しくコピーされ、呼び出し元のコードが必要なベクトルを操作およびテストできることを意味します。

vector<AttrValue> QueryEvaluator::getCandidateList(...)
{
    ...
    return &values;
}

サイドノート:

また、コードでポインターを使用しないようにする必要があります。ポインタは所有権を伝えません。つまり、オブジェクトの削除の責任者がわからないということです。この場合、呼び出し元がオブジェクトへのアクセスを許可し、所有権が保持されるため (値で返さないことにしたと仮定すると)、おそらく参照の方が良いでしょう (決して NULL を返すことはありません)。

于 2013-01-25T11:21:23.773 に答える