假设我想编写工厂方法,该方法应该在堆上分配异构对象并将它们返回给调用者。我正在考虑这样设计 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);
我的问题是:“这是惯用的吗?如果不是,正确的方法是什么?”
我能想到的替代方法包括返回 auto_ptr
的 struct
,或者编写工厂 API 来获取原始指针引用。它们都需要编写更多代码,而后者在异常安全方面还有其他问题。
Suppose I want to write factory method that is supposed to allocate heterogeneous objects on the heap and return them to the caller. I am thinking of designing the API like this:
bool MakeEm(auto_ptr<Foo>& outFoo, auto_ptr<Bar>& outBar) {
...
if (...) {
return false;
}
outFoo.reset(new Foo(...));
outBar.reset(new Bar(...));
return true;
}
This allows a caller to do this:
auto_ptr<Foo> foo;
auto_ptr<Bar> bar;
MakeEm(foo, bar);
My question is: "Is this idiomatic? If not, what is the right way to do this?"
The alternative approaches I can think of include returning a struct
of auto_ptr
s, or writing the factory API to take raw pointer references. They both require writing more code, and the latter has other gotchyas when it comes to exception safety.
发布评论
评论(5)
询问某事是惯用的,会给你一些非常主观的答案。
然而,总的来说,我认为 auto_ptr 是传达所有权的好方法,因此作为类工厂的返回 - 这可能是一件好事。
我想重构这一点,这样
Asking of something is idiomatic can get you some very subjective answers.
In general, however, I think auto_ptr is a great way to convey ownership, so as a return from a class factory - it's probably a Good Thing.
I would want to refactor this, such that
您不必构建自己的结构来返回两个值 - 您可以使用 std::pair。在这种情况下,返回两个值并没有太多语法开销。这个解决方案确实存在一个问题,即“.first”和“.second”不是非常具有描述性的名称,但如果涉及的类型和函数的名称使意图足够清晰,那么这不一定是问题。
如果您使用的是 C++0x,则可以使用 unique_ptr 代替 auto_ptr,并且调用者可以使用 auto 而不必键入较长的 std::pair、std::unique_ptr> 。 。如果您不使用 C++0x,您可以考虑使用 typedef。
如果您返回这两个值,那么您将没有空间容纳该布尔值。您可以使用 C++0x 元组返回所有三个值。您还可以通过引发异常或返回空指针来指示错误。我更喜欢一个例外,假设错误是罕见/异常的。
正如其他答案所指出的,通常最好有两个单独的函数,每个函数返回一个对象。如果您不能这样做,因为两个对象的初始化是紧密相连的,那么您可以创建一个封装初始化的类。您可以将必要的信息传递给构造函数以生成两个对象(需要异常来发出错误信号),然后在该类上使用两个方法,每个方法生成一个对象。
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.
我们假设返回值
false
表示“不查看输出参数”。然后我要做的就是去掉 bool 返回值,返回一个具有所需 auto_pointers 的结构或对,并在错误条件下抛出。
Let's assume that a return value of
false
means "don't look at the output parameters".Then what I would do is get rid of the bool return value, return a struct or pair that has the auto_pointers you want, and
throw
in the error condition.通常,当您有 auto_ptr 参数时,它们不是引用。
这是因为当您将某些内容传递给采用 auto_ptr 的函数时,您希望该函数获得所有权。如果您通过引用传递,它实际上并不获取该对象(它可能会获取该对象)。
这是一个微妙的点,但最终您需要看看您的界面试图向用户传达什么信息。
此外,您似乎将其用作 out 参数。
就我个人而言,我从未见过这个用例(但我可以看到它),只是记录您想要做什么,更重要的是为什么。
Usually when you have auto_ptr parameters they are not references.
This is because when you pass something to a function that takes auto_ptr you are expecting that function to take ownership. If you are passing by reference it does not actually take the object (it may take the object).
Its a subtle point, but in the end you need to look at what your interface is trying to say to the user.
Also you seem to be using it as an out parameter.
Personally I have never seen this use case (but I can see it) just document what you are trying to do and more importantly why.
作为一般规则,如果它涉及
auto_ptr
,则它不是惯用的。一般来说,该结构并不是很惯用——通常,您将为每个函数创建一个函数,按值返回并在失败时抛出异常,如果您需要共享变量,请将其设为对象。As a general rule, if it involves
auto_ptr
, it's not idiomatic. In general, the structure is not idiomatic too- normally, you'd make one function for each, return by value and throw an exception if they fail, and if you need to share variables, make it an object.