【问题标题】:Combining multiple objects in a single return object在单个返回对象中组合多个对象
【发布时间】:2013-01-08 12:52:23
【问题描述】:

我想从方法调用中返回一个signle对象,其中包含在该方法中创建的多个对象。

Results calculate() {

    Foo f;
    Bar b;
    ...
    Results r(f, b);
    return r;
}


class Results {

private:
    ?

public:

    Results(Foo& f, Bar& b);

    Foo? getFoo();

    Bar? getBar();

}

a) Results 成员变量应该是指针吗?

private:
    Foo* foo;
    Bar* bar;


public:
    Results(Foo& f, Bar& b) {
        this->foo = &f;
        this->bar = &b;
    }

b) getFoo 应该返回 FooFoo& 还是 Foo*

【问题讨论】:

  • 您到底想达到什么目的?也许通过引用传递对象比创建一个包含要返回的对象的新对象更好。
  • @Skalli 方法calculate 创建了多个对象,这些对象只能放在一起才有意义。通过引用传递输出参数对我来说在风格上很奇怪,有什么优势?
  • 好吧,没有野指针是一个优势。但我喜欢 mfontaninis 解决方案。但是,如果您有两个以上的对象,则需要一种不同的方法。

标签: c++ oop pointers reference


【解决方案1】:

使用 C++11 的元组(或 boost 的,否则),你基本上是在重新实现它们:

#include <tuple>

std::tuple<Foo, Bar> calculate() {
    Foo f;
    Bar b;
    ...
    return std::make_tuple(f, b);
}

void test() {
    Foo f;
    Bar b;
    std::tie(f, b) = calculate();
}

请注意,这可以轻松扩展为返回 2 个以上的对象。这就是我使用 std::tuple 而不是 std::pair 的原因,正如另一个答案中提到的那样。

【讨论】:

  • 这是一个非常糟糕的建议。 tuplepair 之类的东西非常适合快速原型设计,但您真的不想在生产代码中看到它们。像“first”这样的名字根本不提供任何有用的信息,并且使阅读代码变得更加困难。
  • @JamesKanze 即使我同意你的观点,OP 似乎只是使用此代码来提供“多个返回值”。因此,我认为您在我的代码 sn-p 中提到的内容实际上没有问题;使用 std::tie 将避免与元组交互。
  • @mfontanini 元组的一个缺点是元组的部分未命名。如果我返回std::tuple&lt;Foo, Foo, Bar&gt; 并且区分第一个和第二个Foo 很重要怎么办?为了清楚起见,我宁愿使用 getThisFoogetThatFoo 方法。
【解决方案2】:

不,不要这样做。因为在calculate() 中,Foo fBar b 是本地对象,当您从此函数返回时,它们将消失。将fb 复制到Results

class Results {
private:
    Foo foo;
    Bar bar;

public:
    Results(const Foo& f, const Bar& b) : foo(f), bar(b) {}

    const Foo &getFoo() const { return foo; }
    const Bar &getBar() const { return bar; }
}

更简单的方法是使用 std::pair 并返回它

std::pair<Foo, Bar> calculate() {
    Foo f;
    Bar b;
    ...
    return std::make_pair(f, b);
}

【讨论】:

    【解决方案3】:

    a) 不会。通过初始化calculate() 中的值,这些变量会在函数完成执行时“死亡”。这样,你之前初始化的指针就会指向一个空的空间。

    b) 考虑到私有成员不是指针,您可以根据需要执行此操作。如果您希望数据“停留”在对象内,您可以使用指针或引用(不管是哪一个)。否则取“正常”变量。

    【讨论】:

      【解决方案4】:

      a) 结果成员变量应按值保存。否则,您将返回本地、超出范围的数据的地址(或引用)。

      b) getFoo 应该返回对对象的 const 引用,或者在 POD 类型的情况下按值返回。

      也就是说,考虑更改您的接口以接受 Foo& 和 Bar& 类型的 i/o 参数,填充内部变量而不返回它们。这将避免返回值的两个副本,否则这是必需的。

      你也可以用 std::tuple 替换你的 Results 类:

      std::tuple<Foo,Bar> calculate() {
      
          Foo f;
          Bar b;
          ...
          return std::tuple(f,b);
      }
      
      // client code:
      Foo foo;
      Bar bar;
      
      std::tie(foo, bar) = calculate();
      

      编辑:如果您不使用 C++11(对于 std::tuple),请考虑使用 boost::tuple

      【讨论】:

        【解决方案5】:

        我仍然有点不确定你想要达到什么目标,但目前你会遇到麻烦: a 和 b 在计算中的堆栈上,您基本上返回指向它们的指针。但是,一旦计算完成并且ab 超出范围,您就有了野指针。这很糟糕。
        如果您有更多返回值,请创建智能指针并将它们返回到一个对象中。
        或者将指针传递给ab 以计算并在计算中使用new 在堆上创建对象。但请注意,您必须自己删除它们,否则最终会导致内存泄漏。 所以基本上,如果你在result 中有两个以上的对象,那么添加一个智能指针,如std::auto_ptrstd::shared_ptr(或者如果你不使用C++11 boost::shared_ptr

        【讨论】:

          猜你喜欢
          • 2022-11-08
          • 2013-06-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-08-08
          • 1970-01-01
          • 2014-03-24
          相关资源
          最近更新 更多