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

Pointer to vector: size is correct in function but 0 in caller

本文关键字:调用者 指针 函数      更新时间:2023-10-16

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

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;
}

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

尝试:

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

我尝试了一个简单的程序,它似乎很好...

当 getCandidate List 函数返回时,将释放临时向量。程序具有未定义的行为。

您的向量似乎是在堆栈上声明的,因此当它超出范围时(当函数退出时)将被销毁。 如果要返回指向向量的指针,请改为将其分配给堆上

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(...) {

有很多有趣的事情需要考虑:

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),因为这赋予调用方对对象的访问权限将保留所有权(假设您决定不按值返回)。