在方法中返回静态变量是个坏主意

Is returning static variables in methods a bad idea?

本文关键字:变量 方法 返回 静态      更新时间:2023-10-16

我到处找了找,似乎找不到问题的答案。我正在做一个项目,在这个项目中,我必须为向量和多项式之间的运算重新定义一些运算符(+-*等)。据我所知,如果我们只是调用运算符(即vect1+vect2;而不是vect1 += vect2;)而不将结果放在任何位置,那么这些运算符应该返回对象的副本,以免直接修改它们。

现在,我已经看到了使用静态变量是一种糟糕的做法,但当一个方法需要返回结果的副本而不是修改对象时,我该如何避免这样做呢?

这里和这里的问题并没有真正帮助,因为它们没有解决我的特定问题。

下面是我的意思的一个例子:

template <class elem>
Vect_variable<elem>& Vect_variable<elem>::operator+(const Vect_variable& operand)
{
    if (taille >= operand.taille)
        {
        static Vect_variable<elem> temp_v;
        temp_v = *this;
        for (std::size_t i = 0; i<operand.taille; i++)   
            {
            temp_v[i] += operand.vecteur[i];
            }
        return temp_v;
        }
    else
        {
        static Vect_variable<elem> temp_v;
        temp_v = operand;
        for(std::size_t i = 0; i<taille; i++)
            {
            temp_v[i] += vecteur[i];
            }
        return temp_v;
        }
}

在这种情况下,您可以看到我正在为所使用的临时变量创建静态Vect_variable。有别的办法吗?

是。不要将变量设为static。这样,每个对函数的调用都会得到自己的新变量,然后返回。

此外,它是自动的(在堆栈上)而不是静态的,您可以一次性声明变量并初始化它。

我没有注意到你正在返回向量的引用。不要那样做。按值返回。

template <class elem>
Vect_variable<elem> Vect_variable<elem>::operator+(const Vect_variable& operand)
{
    if (taille >= operand.taille)
        {
        Vect_variable<elem> temp_v = *this;
        for (std::size_t i = 0; i<operand.taille; i++)   
            {
            temp_v[i] += operand.vecteur[i];
            }
        return temp_v;
        }
    else
        {
        Vect_variable<elem> temp_v = operand;
        for(std::size_t i = 0; i<taille; i++)
            {
            temp_v[i] += vecteur[i];
            }
        return temp_v;
        }
}

接下来要做的是注意,您在两个分支中执行的几乎是相同的操作。这只是取决于哪条尾巴更短。所以使用一对指针:

{
    decltype(this) one, two;
    if (taille >= operand.taille)
        {
        one = this;
        two = &operand;
        }
    else
        {
        one = &operand;
        two = this;
    }
    Vect_variable<elem> temp_v = *one;
    for (std::size_t i = 0; i<two->taille; i++)   
        {
        temp_v[i] += two->vecteur[i];
        }
    return temp_v;
}

最后的评论是,通常最好先写operator +=,然后把operator +写成一个带有签名的非成员二进制函数:

TYPE operator +(TYPE lhs, const TYPE& rhs)
{
    lhs += rhs;
    return lhs;
}

请注意,lhs获取(因此您已经有了自己的副本)。非成员函数的优点是,如果有任何到TYPE的转换函数,它们将在左手边和右手边对称操作。

稳健而简单的方法是按值返回一个(非静态)局部变量。在某些情况下,这也是有效的方法。

如果您非常关心效率,那么对于两个输入中的一个是右值的情况,您需要一个替代执行路径。在这种情况下,您根本不需要局部变量。相反,您希望通过右值引用获取输入,修改它并通过右值参考返回它。

为了避免重复代码过多,您可能需要定义一个operator+=,并将实际工作放在该方法中,并让operator+的所有版本将工作委托给operator+=

在某些情况下,通过引用返回static变量比以上所有情况都更有效。但这种情况并不多,而且充满了足够多的危险,你不应该做出这样的选择。

看到您对前面的答案所做的评论后:您是正确的,通过引用返回static避免了从虚拟函数的重写中获得多态返回的大问题。但它这样做是以制造自身问题为代价的。举一个简单的例子,假设有人使用您的+来计算A+(B+C)。不要问为什么他们放了那些不合适的()。只是意识到他们没有办法知道他们不应该。因此,您的操作符将B复制到一个静态并将C添加到该静态,然后将A复制到同一个静态,并将该静态添加到其中并返回2A。虽然这个例子是人为设计的,但如果+返回对静态的引用,它只是可能会出现严重错误的许多事情之一。