用C++返回类的最佳方法

Best Way to Return a Class in C++

本文关键字:最佳 方法 C++ 返回      更新时间:2023-10-16

我正在为一个项目编写C++向量类,我很难决定如何最好地编写一些方法。在我开始之前,我会说这个类有一个很好的复制构造函数和赋值运算符(这将在一秒钟内相关)。该类有一组静态方法,当我想确保两个参数都没有更改时,这些方法会返回向量,它们具有以下签名:

Vector* Vector::subtract(const Vector* v, const Vector* u)
{
double outX = v->myX - u->myX;
double outY = v->myY - u->myY;
double outZ = v->myZ - u->myZ;
return new Vector(outX, outY, outZ);
}

我遇到的问题是,如果我能帮助的话,我不想返回指针。所以我做了一些测试,并意识到如果我只说

return Vector(outX, outY, outZ)

然后像一样分配结果

Vector foo = Vector::subtract(bar, temp)

它将创建一个副本并运行良好。这就是我的问题所在:我刚刚调用了构造函数两次(本质上),有办法绕过它吗?其次,如果我用这个方法作为另一种方法的论据,比如

foo.multiply(&Vector::subtract(foo, bar), 5)

它还会创建一个副本吗?还是我只是传递了Vector::减法方法中超出范围的指针?

更普遍地说,什么是最好的(或者至少有更好的)方法来做到这一点?

我刚刚调用了构造函数两次(本质上)有没有方法绕过那个?

您听说过退货价值优化吗?您无需执行任何操作。编译器很可能会为您消除副本。现在,如果您使用C++11并且Vector类管理资源,那么您也可以声明一个移动构造函数,以便在编译器决定不能执行RVO时移动返回值。然而,看起来类只包含3个值,如果是这样的话,复制将和移动一样高效。

&矢量::减去(foo,bar)

&的作用是什么?那是个错误吗?此外,成员函数未声明为static,因此语法错误。无论如何,假设subtract返回了一个副本,它将返回一个副本并将其作为参数传递给multiply函数。

此外,在另一个注意事项上,Vector* Vector::subtract(const Vector* v, const Vector* u) 会更好地作为Vector* Vector::subtract(const Vector& v, const Vector& u),这使得在传递减法等参数时语法更干净。

因此,更改您的代码时,会出现以下情况:

Vector Vector::subtract(const Vector& v, const Vector& u)
{
return Vector(v.myX - u.myX, v.myY - u.myY, v.myZ - u.myZ);
}

向动态分配的对象返回指针/引用从来都不是一条路。显而易见的例子是,如果您的函数被递归调用,谁负责取消分配内存?

我从Scott Meyers的一本书中读到,唯一安全的方法是返回对象本身。IIRC可以帮助编译器消除这些本质上是临时的对象(从一个函数返回到另一个函数,而不将每个对象分配给另一个),其中一种方法是使其匿名(也称为返回值优化,感谢In silico提醒我)。像这样

return Vector(outX, outY, outZ);

与相反

Vector v(outX, outY, outZ);
return v;

所以我为你的减法提出的签名可以归结为:

Vector Vector::subtract(const Vector& v, const Vector& u)

您应该尽可能避免指针,不仅在返回类型中,而且在函数的参数中。尽可能首选引用,必要时使用指针。

如果您更改函数以通过引用获取参数并通过值返回。当在域中有意义时,考虑重载运算符(我认为这里就是这样):

class Vector { ... };
Vector operator+( Vector const& lhs, Vector const& rhs ) {
return Vector( lhs.x+rhs.x, lhs.y+rhs.y, lhs.z+rhs.y );
}
Vector operator*( Vector const& lhs, Vector const& rhs ) { ... }

然后你可以随意连锁操作:

Vector a(...), b(...);
Vector c = (a + b) * c;

现在大多数编译器都会实现所谓的返回值优化(RVO)来解决这个问题。除非真的有必要,否则不应该返回指针,这是对的。话虽如此,您可能应该使用参考资料。总而言之,如果我要写这个方法,我会这样写:

Vector Vector::subtract(const Vector& v, const Vector& u)
{
return Vector(v.myX - u.myX, v.myY - u.myY, v.myZ - u.myZ);
}