【问题标题】:Returning an object from a function C++ [closed]从函数 C++ 返回一个对象 [关闭]
【发布时间】:2013-03-26 21:15:09
【问题描述】:

假设我有一个变量指向我创建的对象。对于这个例子,假设我有一个代表一张卡片的对象,它有 2 个成员 - 等级和花色。

接下来,假设我初始化了我创建的对象结构,所以我现在有一个带有等级和花色的卡片对象。

我的问题是,如果我想要一个返回我创建的卡片对象的函数怎么办: 我想做这样的事情:

Card* playerCard = foo()

我知道 playerCard 指向一个卡片对象,那么这是否意味着 foo() 也必须返回一个卡片对象?有没有其他方法可以解决这个问题?

基本上我希望我的函数生成卡片,并且 playerCard 应该等于生成的卡片。我不知道返回一个对象是否是解决问题最直接的方法,这就是为什么我还要询问是否有任何替代解决方案。

感谢您的帮助!

【问题讨论】:

  • 我不确定您的所有要求,但我认为返回 Card 而不是 Card* 应该就可以了。

标签: c++ function computer-science


【解决方案1】:

我将逐步从坏方法变为好方法。

首先,这是错误的做法:

Card* foo() {
  Card c;
  return &c;
}

绝对不要那样做。 Card c 将在 foo 的末尾被销毁,因此您返回的指针将指向无效对象。

可以这样做:

Card* foo() {
  return new Card();
}

new Card()创建的卡片具有动态存储时长,所以在foo结束时不会被销毁。因此返回的指针仍然指向该卡。然后您可以使用指针并确保安全。

但是,这还有另一个缺点。调用foo 的人不清楚,但他们现在负责对返回的指针执行delete,以确保没有内存泄漏。相反,最好使用智能指针将所有权清楚地传递给调用者:

std::unique_ptr<Card> foo() {
  return std::unique_ptr<Card>(new Card());
}

但是,如果您根本不需要动态分配,那就更好了。为什么不直接返回 Card 并让它从函数中复制出来呢?你可以这样做:

Card foo() {
  return Card();
}

然后,您可以像这样调用函数,而不是分配给指针:

Card c = foo();

当然,这取决于您允许这样做的要求。如果您想以多态方式使用Card*,则需要使用其中一种指针方法。否则你最终会分割你的 Card 衍生品。

【讨论】:

  • +1。你今天势不可挡;)
  • "为什么不直接返回Card?"因为你可能想从Card 继承,在这种情况下你有很大的切片危险。
  • @MattPhillips 当然,这就是我问的原因。 :D
  • 你做到了?提请注意(最近开发的)unique_ptr 选项很棒,但是对于完美的答案,IMO 你会明确提到返回Card 的切片危险,尤其是。因为那里有很多不同的卡,它很可能是多态候选者。
  • 非常感谢 - 我最终测试了您建议的所有不同实现,看看它们是如何工作的。如果我有声望,我会投票,但我会接受这个答案。
【解决方案2】:

你正在返回一个指向对象的指针,而不是一个对象。

我不确定你的问题到底是什么,所以我只是给你一个完整的例子:

struct card {int rank; int suit};

card make_a_card() {
   return card{10,3};
}

int main() {
    card a_card = make_a_card();
    // a_card == card{10,3}
}

您很少希望从函数返回原始指针。速度不是必需的(事实上,由于 RVO 和移动语义,它实际上最终可能会变慢),所以除了运行时多态性(即对于工厂方法)之外,几乎没有理由这样做。

【讨论】:

    【解决方案3】:

    如果函数 foo() 返回一个指向已创建的 Card 对象的指针,则为它分配一个 Card 指针应该可以正常工作。重要的是要记住,您实际上传递的是同一张牌,而不是副本或任何东西。

    【讨论】:

      【解决方案4】:

      如果你想返回一个指针,你可以使用动态内存分配,否则你的指针在foo 执行后将指向任何东西(参见Dangling pointers):

      Card* foo() {
          Card* ret = new Card(...);
          ...
          return ret;
      }
      

      上述代码的另一个版本将使用标准库中的std::unique_ptr,以使您的代码的客户端程序员清楚您正在返回一个动态分配的指针。它是一个智能指针,因此它会在其作用域的末尾自动释放自己(不在函数末尾,因为它被复制到调用块)。

      否则,如果您的对象/结构复制成本不高,您可以按值返回它,从而导致复制:

      Card foo() {
          Card ret(...);
          ...
          return ret;
      }
      

      【讨论】:

      • 在第二个代码示例中很可能会省略副本,因此不应考虑复制费用。
      • @juanchopanza,这真的取决于具体编译器的实现,不是吗?
      • 是的,确实如此,但现在很难找到不这样做的人了。
      猜你喜欢
      • 1970-01-01
      • 2014-10-15
      • 1970-01-01
      • 2021-08-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-22
      • 2021-09-28
      相关资源
      最近更新 更多