简体   繁体   中英

C++ Is using auto_ptr references as out variables idiomatic?

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.

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

  1. You return one object instead of 2. If you need 2 objects that are so tightly coupled they cannot exist without each other I'd say you have a strong case for is-a or has-a refactoring.
  2. This is C++. Really ask yourself if you should return a value indicating success, forcing the consumer of your factory to have to check every time. Throw exceptions or pass exceptions from the constructors of your classes in the factory. Would you ever want to be OK with false and try to operate on uninitialized auto_ptr's?

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.

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.

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 .

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM