Reputation: 22448
I want to return a signle object from a method call which contains multiple objects created in the method.
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) Should Results
member variables be pointers?
private:
Foo* foo;
Bar* bar;
public:
Results(Foo& f, Bar& b) {
this->foo = &f;
this->bar = &b;
}
b) Should getFoo
return Foo
, Foo&
or Foo*
?
Upvotes: 0
Views: 369
Reputation: 2817
I'm still a bit uncertain what you're trying to achieve, but currently you'd run into trouble:
a and b are on the stack in calculate, you essentially return pointers to them. But as soon as calculate is finished and a
and b
go out of scope, you have wild pointers. That's very bad.
Create smart pointers and return them in an object if you have more return values.
Or pass pointers to a
and b
to calculate and create the objects on the heap with new
in calculate. But be aware that you have to delete them by yourself otherwise you end up with memory leaks.
So basically, if you have more than two objects in result
, then add a smart pointer like std::auto_ptr
or std::shared_ptr
(or if you don't use C++11 boost::shared_ptr
)
Upvotes: 0
Reputation: 74078
No, don't do it this way. Because in calculate()
, Foo f
and Bar b
are local objects, which will go away, when you return from this function. Copy f
and b
into 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; }
}
An easier way could be to use a std::pair
and return that instead
std::pair<Foo, Bar> calculate() {
Foo f;
Bar b;
...
return std::make_pair(f, b);
}
Upvotes: 2
Reputation: 27385
a) The results member variables should be held by value. Otherwise you return the addresses (or references) of local, out-of-scope data.
b) getFoo should return a const reference to the object, or return by value, in case of POD types.
That said, consider changing your interface to accept i/o parameters of the types Foo& and Bar&, populate the variables inside and not return them. This would avoid two copies of the returned values, which are necessary otherwise.
You can also replace your Results
class with a std::tuple:
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();
Edit: If you do not use C++11 (for std::tuple
) consider boost::tuple
instead.
Upvotes: 0
Reputation:
a) No. By initializing the values in calculate()
, these variables "die" when the function finished executing. This way, the pointers you initialized before will point to an empty space.
b) Considering the private members not to be pointers, you can do this as you want. If you want the data to "stay" inside the object, you may take pointers or references (does not matter which one). Take "normal" variables otherwise.
Upvotes: 1
Reputation: 21910
Use C++11's tuples(or boost's, otherwise), you're basically reimplementing them:
#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();
}
Note that this could be easily extended to return more than 2 objects. That's why I used std::tuple
rather than std::pair
as mentioned in another answer.
Upvotes: 4