2

在 Java 中,所有类都是真正的引用,我这样做:

Car getCar(int mileage)
{
  Car car = new Car();

  car.setMileage(mileage);
  return car;
}

在 C++ 中,我该怎么做?我可以将其放入参考:

void getCar(int mileage, Car& car)
{
  car.setMileage(mileage);
  return true;
}

或者,我可以创建一个新对象:

Car* getCar(int mileage)
{
  Car* car = new Car;

  car.setMileage(mileage);
  return car;
}

但是,调用者也负责删除car.

我不想返回一个指针。我要还车:

Car getCar(int mileage)
{
  Car car;

  car.setMileage(mileage);
  return car;
}

但是,当然,car是一个局部变量,一旦函数完成,它将被删除。

通常这样做的“标准”方式是什么?哪个是最好的方法,为什么?

4

4 回答 4

4

您的最后一段代码很好——您返回的是局部变量的值,而不是局部变量本身,所以会发生什么(至少在理论上)该值将从局部变量复制到调用者的任何位置分配它。

这基本上与我有类似的东西相同:

int f() { 
    int x = 0; 
    return x;
}

同样,我们正在返回一个值。该值恰好来自一个局部变量,但我们仍然返回该值,而不是变量。

就“至少在理论上”部分而言,大多数编译器都可以对此进行优化,因此根本不会发生复制。有一些特殊规则允许编译器跳过执行此复制,即使复制会产生您希望在复制发生时看到的外部可见副作用(例如,如果您编写了一个复制构造函数,它在副本发生了)。

于 2012-05-02T03:41:18.553 回答
2

您的最后一个示例是返回对象的正确且惯用的方法:

Car getCar(int mileage)
{
  Car car;

  car.setMileage(mileage);
  return car;
}

是的,car将在函数结束时被删除,但不会在它被复制到返回的对象之前。你可以像这样调用这个函数:

{
    Car myCar;
    myCar = getCar(42);
}

car本地的被getCar复制到调用环境的myCar.


您不能也不能做的是返回对局部变量的引用或指针。这是错误的:

Car& getCar(int mileage)
{
  Car car;
  return car;
}

这也是错误的:

Car* getCar(int mileage)
{
  Car car;
  return &car;
}

在每种情况下,您都允许调用函数访问不再存在的对象。

您不能返回指向本地的指针或引用。您可以返回本地的副本。

于 2012-05-02T03:40:59.667 回答
1
Car getCar(int mileage) {   Car car = new Car();    car.setMileage(mileage);   return car; }

在 C++ 中,我该怎么做?我可以将其放入参考:

void getCar(int mileage, Car& car) {   car.setMileage(mileage);   return true; }

是的——没关系,虽然你不能为void函数返回任何东西。

或者,我可以创建一个新对象:

Car* getCar(int mileage) {   Car* car = new Car;    car.setMileage(mileage);   return car; }

但是,调用者也负责删除汽车。

没错……但是您可以使用智能指针来使其更加可靠和方便。

我不想返回一个指针。我要还车:

Car getCar(int mileage) {   Car car;    car.setMileage(mileage);   return car; }

但是当然,car 是一个局部变量,一旦函数完成就会被删除。

不正确 - 这很完美 - car 对象由 value返回,这意味着它可以在堆栈上供调用者在表达式中使用,包括作为在其他地方复制的源。

通常这样做的“标准”方式是什么?哪个是最好的方法,为什么?

通常,上面的最后一个版本是“标准”方式 - 它通常足够高效(通常优化构建时最佳),避免混乱的指针,并且直观且简单。当然,从可以做到这一点的 C++ 到需要到处使用new变量的 Java 是很痛苦的。

于 2012-05-02T03:44:28.017 回答
0

需要很好理解的重要区别是,在 Java 中对象是通过引用进行的,并通过它们的地址来标识。

在 C++ 中,它们是“值”(如int)和......由它们的地址标识:-((这是规范调用对象的方式)

无论成语说什么,您都必须做出决定:对您来说什么是重要的:价值还是地址?

Person具有相同值的两个name代表同一个(在现实世界中)person,或者两个实词同音person -s?在您的上下文中,多态性有多重要?(是否有多种“-s”由不同的Person-派生表示)?

这不是“成语”所说的。这是您必须建立的约定。

如果您想使用值,请按值返回(注意:在大多数情况下,编译器会忽略返回时复制,因此它不是性能限制器),但忘记了多态性。但是,如果您的对象包含一些资源,请确保它们也遵循“按值”范式,否则请准备好覆盖构造函数、析构函数、复制构造函数、移动构造函数和赋值以正确处理资源所有权。或者......使用按值资源管理器将它们包装起来(智能指针可以做到这一点)。

如果您想使用地址并需要多态性,那么请准备好在堆上分配对象,使用指针,并正确管理分配/释放(最终在智能指针的帮助下,如unique_ptror shared_ptr)。

对于这两种情况,都有一系列的习语和模式,但第一点是了解你的目标是什么模型,并且表现得连贯。

但是你无论如何都不会得到一件事:C++ 永远不会“像 java”。所以不要试图模仿它。按值或按指针(按引用变化不大),您必须以另一种方式思考。

于 2012-05-02T07:30:36.143 回答