tags:

views:

155

answers:

5

I want to return two values, one of which is a new object. I can do this using std::pair:

class A {
//...
};

std::pair<A*, int> getA()
{
   A* a = new A;
   //...
}

To make the code exception-safe, I would like to do:

std::pair<std::auto_ptr<A>, int> getA()
{
    std::auto_ptr<A> a(new A); 
    //...
}

But this won't compile as the auto_ptr cannot be copied without modifying the auto_ptr being copied. Ok, this means auto_ptr does not compose well like other types (in one more way). What is a good way of returning a new object in this case?

One alternative is to return a shared_ptr and another is an inout reference. But I am looking for some other alternative. I can do something like:

class AGetter
{
    void getAExecute()
    {
         //...
         // set a_ and i_
    }
    std::auto_ptr<A> getA() const
    {
         return a_.release();
    }
    int getInt() const
    {
         return i_;
    }
    private:
    std::auto_ptr<A> a_;
    int i_;
};

Is there a better way?

+1  A: 

It's not pretty, but you could return the other value through a pointer or reference argument:

int i;
std::auto_ptr<A> a = getA(&i);
Nathan Kitchen
+5  A: 

There are two major ways to handle this problem:

  1. Do the cleanup yourself, via try/catch.
  2. Use some kind of automated memory management, like shared_ptr.

auto_ptr doesn't really work in these sorts of cases, as you discovered, but the new standard and Boost both contain reference-counted pointers that do what you want. Let us know what you don't like about shared_ptr, and maybe we can suggest an alternative.

David Seiler
shared_ptr is slightly/trivially inefficient and viral. Not very strong arguments against shared_ptr, but still make a factor against them (in 10% of the cases).
Amit Kumar
fortunately, the next standard contains unique_ptr, that can be moved along with the pair containing it.
Johannes Schaub - litb
+1  A: 

Why not through two reference parameters?

class AGetter
{
    // ..
    void get(std::auto_ptr<A>& a, int& i)
    {
         a = a_.release();
         i = i_;
    }
    // ..
};
Magnus Skog
That is what i meant by inout references. Inout references are ok, but you'll agree still a compromise (the function signature does not make clear the effects of calling the function).
Amit Kumar
+3  A: 

A shared_ptr would be ideal in that situation, but if you really don't want to use those you could return an auto_ptr to a pair containing the object and the int instead.

Gab Royer
+2  A: 

Just create a new class and return that class

class Result
{
   A* a;
   int i;
public:
   Result( A*a, int i ) : a(a), i(i) {
   }
   ~Result() { 
      delete a; 
   }
   // access functions, copy constructor, ...
};

Result getA() {
   //...    
   return Result(new A, intValue);  
}
TimW