如何避免vector从方法返回后被销毁

C++: How to avoid vector from being destroyed after returning from method?

本文关键字:返回 方法 何避免 vector      更新时间:2023-10-16

我试图重载Polynomial类的除法运算符/,但算法本身是无关紧要的。问题是c++似乎正在破坏我的多项式,当我试图返回它的一些未知的原因。

这是类的相关部分:

class Polynomial
{
    public:
        .........
        Polynomial &operator/(const double &) const;
    private:
        int DEGREE;
        std::vector<double> poly_terms; // stores the polynomial coefficients
        .........
}

这个方法我不能正常工作:

Polynomial &Polynomial::operator/(const double &rhs) const
{
    Polynomial result(10); //create new polynomial object with a maximum degree of 10
    double buffer;
    for(int i = 0; i <= DEGREE; i++)
    {
        buffer = poly_terms[i]; //poly_terms is of type vector<double>
        result.setCoeff(i, buffer / rhs); //this method assigns (buffer / rhs) to the i-th index of result's vector data-member.
    }
    return result; //return Polynomial instance
}

在执行return子句之前,调试器显示result对象的所有数据成员的值都正确地设置为算法应该设置的值,包括vector数据成员。因此,在return返回之前,result是100%正确构建的,因此到目前为止,该方法的逻辑似乎很好。

但是在执行return语句之后,一切都失败了。由于某种原因,返回的对象将其vector数据成员更改为空的vector(奇怪的是,所有其他不是对象的数据成员,如DEGREE,都保持原样)。我不确定它是否以某种方式被清空的相同向量对象,或者如果它是包含该向量对象的多项式对象的失败副本。

有谁知道为什么会发生这种情况,我该如何避免?

UPDATE1: 我应该提到的是,我还尝试通过使用new在此方法中创建Polynomial对象。我也试着不通过删除&来返回引用,所以有一个像Polynomial Polynomial::operator/(const double &rhs) const这样的标题。但是这两种方法都会对vector数据成员产生类似的不良影响。

更新2:似乎我能够追踪到这个问题,感谢那些提到我不应该返回引用的人。问题是需要重载复制构造函数和重载赋值操作符来手动执行vector数据成员的拷贝(不确定两者是否都需要,我刚刚实现了所有这3件事,现在它工作得很好)。谢谢大家帮忙解决这个问题。

返回对局部变量的引用。任何使用该变量的代码都是未定义的行为。对于您的情况有一个简单的解决方案:删除&

// Notice that the function is not returning a reference anymore
Polynomial Polynomial::operator/(const double &rhs) const
{
    Polynomial result(10); //create new polynomial object with a maximum degree of 10
    double buffer;
    for(int i = 0; i <= DEGREE; i++)
    {
        buffer = poly_terms[i]; //poly_terms is of type vector<double>
        result.setCoeff(i, buffer / rhs); //this method assigns (buffer / rhs) to the i-th index of result's vector data-member.
    }
    return result; //return Polynomial
}

您可能认为它会减慢您的代码,因为它复制了变量result。这是错误的。您的代码将使用复制省略。这意味着没有复制return语句。

即使你的编译器很笨,不使用复制省略,它也会使用类的move构造函数,这仍然比复制快得多。

要阅读有关复制省略的更多信息,请查看此处的文档页面:复制省略

至少在Visual studio中,这段代码应该给你一个警告,因为你使用了一个将被销毁的临时对象的引用,所以你使用了一个你不知道的引用。这是未定义的行为。

您可以简单地按值返回result来解决这个问题。如果矢量很大,并且您担心按值返回的性能,则可以为Polynomial设置移动构造函数,在该构造函数中移动矢量而不是复制它。

我发现你的代码有三个问题(尽管不是所有的问题都导致了你的麻烦):

  1. 正如其他人指出的那样,返回一个对象的引用,该对象在程序退出操作符重载函数时立即死亡。你可以直接返回多项式对象

  2. 循环使用从0到DEGREE的索引(因此DEGREE + 1项被修改)。我假设DEGREE是从多项式构造函数的int输入参数定义的东西。我希望循环从0定义到DEGREE - 1

  3. 我也希望"结果"多项式对象用DEGREE度实例化,而不是硬编码的10