不能从函数返回向量

C++ - Cannot return vector from function

本文关键字:向量 返回 函数 不能      更新时间:2023-10-16

假设以下函数

std::vector<double> LocatePulseEdges(int points, double* signal_x, double* signal_y, double threshold, vector<double> left_edge, vector<double> right_edge){
cout << "1" << endl;
    for (int i=0; i<points; i++){
        if(signal_y[i]<threshold){// left side of the pulse
            left_edge.push_back(signal_x[i]);
            break;
        }
        if(signal_y[i]>threshold){// right side of the pulse
            right_edge.push_back(signal_x[i]);
            break;
        }
    }
cout << "6" << endl;
    return left_edge;
    //return right_edge;
cout << "7" << endl;
}

我在下面的代码中调用这个函数

void Analyze(){
    int points = 90000000;//hSignal->GetNbinsX();
    double* x          = new double[points];           // SIZE limited only by OS/Hardware
    double* y          = new double[points];
    std::vector<double> left;
    std::vector<double> right;
    double threshold = 6234.34;
    Function_to_Fill_X_and_Y();
    LocatePulseEdges(points, x, y, threshold, left, right);
    cout << "First left threshold crossing @ time : " << left[0] << endl;
}

虽然我没有得到编译错误,但当我运行程序时,它在返回语句之前崩溃了。

知道为什么会这样吗?

LocatePulseEdges函数和Analyze函数存在几个缺陷。

首先,如果你打算在一段代码中使用std::vector<double>,为什么不在整个代码中使用它呢?你有:

void Analyze()
{
  //...        
  double* x = new double[points]; 
  double* y = new double[points];
 //...
}

除非您调用了delete [] xdelete [] y,否则该函数存在内存泄漏。你可以直接使用

std::vector<double> x(points), y(points);

和在填充它们的函数中,如果使用c++ 11,则传递x.data()y.data(),如果使用c++ 11,则传递&x[0]&y[0]。这减轻了内存泄漏。

即使你在某个地方有delete [],如果抛出异常,delete []可能会被绕过,导致泄漏。使用std::vector,即使出现异常,vector也会被销毁。


第二,对于LocatePulseEdges函数,传递vector的by (const)引用,而不是value引用。此外,不需要按值返回向量。如果你在函数中创建了一个全新的向量,那么可能会证明返回新向量是合理的,但是你没有这样做。所以返回一个void
void LocatePulseEdges(int points, double* signal_x, double* signal_y, double threshold, vector<double>& left_edge, vector<double>& right_edge)
{
    //...
}

当按值传递vector时,会生成vector的副本,因此left_edge.push_back()调用处理的是临时vector,而不是传递的实际vector。这就是为什么在返回时,向量left_edge是空的。


最后,如果要访问vector中的第一项,检查vector::empty()。不能仅仅假定该元素存在于vector中。

   LocatePulseEdges(points, x.data(), y.data(), threshold, left, right);
   if ( !left.empty() ) 
       cout << "First left threshold crossing @ time : " << left[0] << endl;
   else
       cout << "No threshold's generated" << endl; 

上面的代码假设您接受了对xy变量使用std::vector<double>的建议。

通过引用传递你的left_edge,这样它就可以被你的函数修改:

void LocatePulseEdges((int points, double* signal_x, double* signal_y, double threshold, 
std::vector<double> &left_edge, std::vector<double> &right_edge)
{
    //do your stuff
}

当你给出没有&的参数时,程序复制你的参数的值,然后使用它。所以你不能修改它。使用&传递参数称为通过引用传递。

当你通过引用传递一个对象时,你可以修改它,这样会更快。如果你需要传递一个对象而不修改它,给一个const ref:

void foo(const std::vector<double> &vec)

void foo(std::vector<double> vec)

,并通过const关键字阻止您修改vec

附加说明:

void函数不需要任何返回值,但在许多情况下,最好使用Bool函数

Bool LocatePulseEdges()
{
    //do your stuff
    return True ;
}

这样做可以允许您在出现错误时过早返回False。

根据评论我得到:

  1. 将LocatePulseEdges函数更改为使用引用:

    void LocatePulseEdges((int points, double* signal_x, double* signal_y, double threshold, std::vector<double> &left_edge, std::vector<double> &right_edge) { //do your stuff } 所以你可以在函数

  2. 中改变参数的值
  3. 在访问vector之前检查元素是否存在:

    if (left.size() <= index) { return left[index]; }

  4. 你的代码出了什么问题?for (int i=0; i<points; i++)被执行,因为points = 9000000,但signal_y[i]<threshold永远不会为真(它没有在你的代码中初始化),所以没有插入到left