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

时间:2012-09-20 03:05:24

标签: c++

我正在为一个项目编写一个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方法范围的指针?

更一般地说,最好的方法是什么(或者至少有更好的方法)?

4 个答案:

答案 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;