向量指针:大小在函数中是正确的,但在调用者中是0

时间:2013-01-25 10:58:37

标签: c++ visual-c++ pointers vector

我有一个简单的函数,我简化为只返回一个虚拟列表(以确保它不是一些逻辑错误)

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消息打印出正确的大小,也总是为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;
}

3 个答案:

答案 0 :(得分:4)

您正在从getCandidateList函数返回临时地址,该函数返回时该对象将被释放。访问它是未定义的行为。您可以退出向量,RVO应该应用并删除副本:

尝试:

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

我尝试了一个简单的程序,看起来很好......

当getCandidateList函数返回时释放临时向量。该程序有不确定的行为。

答案 1 :(得分: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(...) {

答案 2 :(得分: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),因为这使得调用者对该对象的访问将保留所有权(假设您决定不按值返回)。