我正在为一个项目编写一个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 :: subtract方法范围的指针?
更一般地说,最好的方法是什么(或者至少有更好的方法)?
答案 0 :(得分:2)
返回指向动态分配对象的指针/引用永远不是可行的方法。显而易见的例子是,如果你的函数是递归调用的,谁负责取消分配那个内存?
我从一本书(Scott Meyers,它是有效的C ++项目#21)中读到,唯一安全的方法是返回对象本身。您可以做的是,IIRC,促进编译器工作,消除这些基本上是临时的对象(从一个函数返回到另一个函数而不是每个被分配给另一个),其中一种方法是使它匿名(也称为返回值优化,感谢In silico提醒我)。像这样
return Vector(outX, outY, outZ);
而不是:
Vector v(outX, outY, outZ);
return v;
所以我提出的减法方法的签名归结为:
Vector Vector::subtract(const Vector& v, const Vector& u)
答案 1 :(得分:2)
我刚刚调用构造函数两次(基本上)有一种方法 绕过那个?
你听说过Return Value Optimization吗?你无需做任何事情。编译器很可能会为您删除副本。现在,如果您使用C ++ 11并且Vector
类管理资源,您也可以声明一个移动构造函数,以便在编译器确定它无法执行RVO时移动返回的值。但是,看起来这个类只有3个值,如果是这样的话,复制就像移动一样有效。
& Vector :: subtract(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);
}
答案 2 :(得分:1)
现在大多数编译器都会实现所谓的返回值优化(RVO)来解决这个问题。除非真的有必要,否则你不应该返回指针。话虽这么说,你应该使用引用。总而言之,如果我要编写这个方法,这就是我写它的方式:
Vector Vector::subtract(const Vector& v, const Vector& u)
{
return Vector(v.myX - u.myX, v.myY - u.myY, v.myZ - u.myZ);
}
答案 3 :(得分:1)
你应该尽可能地避免指针,不仅在返回类型中,而且在函数的参数中。如果可能的话,首选参考,必要时使用指针。
如果更改函数以通过引用获取参数并按值返回。考虑在域中有意义时重载运算符(我相信这是这种情况):
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;