3

假设我想编写工厂方法,该方法应该在堆上分配异构对象并将它们返回给调用者。我正在考虑设计这样的API:

bool MakeEm(auto_ptr<Foo>& outFoo, auto_ptr<Bar>& outBar) {
  ...
  if (...) {
    return false;
  }
  outFoo.reset(new Foo(...));
  outBar.reset(new Bar(...));
  return true;
}

这允许调用者这样做:

auto_ptr<Foo> foo;
auto_ptr<Bar> bar;
MakeEm(foo, bar);

我的问题是:“这是惯用的吗?如果不是,那么正确的方法是什么?”

我能想到的替代方法包括返回 a structof auto_ptrs,或编写工厂 API 以获取原始指针引用。它们都需要编写更多代码,而后者在异常安全方面还有其他问题。

4

5 回答 5

4

询问某事是惯用的,可以得到一些非常主观的答案。但是,总的来说,我认为 auto_ptr 是传达所有权的好方法,因此作为类工厂的回报 - 这可能是一件好事。我想重构这个,这样

  1. 您返回一个对象而不是 2 个。如果您需要 2 个对象紧密耦合,它们彼此之间就无法存在,我会说您有一个强有力的案例来进行 is-a 或 has-a 重构。
  2. 这是 C++。真正问问自己是否应该返回一个表示成功的值,迫使工厂的消费者每次都必须检查。从工厂类的构造函数中抛出异常或传递异常。您是否愿意接受 false 并尝试对未初始化的 auto_ptr 进行操作?
于 2011-07-15T18:13:00.500 回答
1

作为一般规则,如果它涉及auto_ptr,它不是惯用的。通常,该结构不是惯用的 - 通常,您将为每个函数创建一个函数,按值返回并在它们失败时抛出异常,如果您需要共享变量,请将其设为对象。

于 2011-07-15T18:10:09.487 回答
1

让我们假设返回值的false意思是“不看输出参数”。

然后我要做的是摆脱 bool 返回值,返回一个具有您想要的 auto_pointers 的结构或对,并且throw处于错误状态。

于 2011-07-15T18:10:44.090 回答
1

通常当您有 auto_ptr 参数时,它们不是引用。

这是因为当您将某些内容传递给采用 auto_ptr 的函数时,您期望该函数获得所有权。如果您通过引用传递,它实际上并没有获取对象(它可能会获取对象)。

这是一个微妙的点,但最后你需要看看你的界面试图对用户说什么。

此外,您似乎将其用作输出参数。
就我个人而言,我从未见过这个用例(但我可以看到)只是记录你正在尝试做的事情,更重要的是为什么

于 2011-07-15T18:12:06.477 回答
1

You don't have to make up your own struct to return two values - you can use std::pair. In that case there isn't much syntactic overhead in returning the two values. This solution does have the problem that ".first" and ".second" aren't very descriptive names, but if the types involved and the name of the function make the intent clear enough then that's not necessarily a problem.

If you are using C++0x you could use unique_ptr insted of auto_ptr and the caller can use auto instead of having to type the longer std::pair<std::unique_ptr<A>, std::unique_ptr<B>>. If you are not using C++0x you might consider using a typedef for that instead.

If you return the two values then you won't have space for the bool. You could use a C++0x tuple to return all three values. You could also indicate error by throwing an exception or by returning null pointers. I would prefer an exception assuming that the error is rare/exceptional.

As other answers have pointed out, it is often preferable to have two separate functions that each return a single object. If you can't do that because the initialization of the two objects is inextricably linked then you could make a class that encapsulates the initialization. You could pass the necessary information to make the two objects to the constructor (requires exception to signal errors) and then have two methods on that class that yield one object each.

于 2011-07-15T22:07:30.737 回答