tags:

views:

110

answers:

4

In C++, what is the best way to return a collection to client code without using iterators.

Let's say iterators are ruled out because eg the collection is remote. I'd like a signature for a function that returns the collection in the most useful form possible.

By 'best', I mean the best trade-off between clarity and genericity.

My instinct was (where result.push_back(obj) is valid C++):

template <typename T>
void getCollection(T& result);

I wonder if anyone has better ideas, for example that would also support insertions into containers that do not support push_back, or that require transformation of the objects in the collection.

The following, perhaps?

template <typename Func>
void getCollection(Func f); // applies f to all the objects
A: 

My friedns' favorite way of returning a whole bunch of data from a function is by using shared pointers:

boost::shared_ptr<vector<string>>  f()  {
   boost::shared_ptr<vector<string>> vec(new vector<string>());
   vec->push_back(....);
   return vec;
}
Pavel Radzivilovsky
Unnecessary, inefficient, and wrong smart pointer. If you have it, you should be using std::unique_ptr, if not you should be using std::auto_ptr. Once in a shared_ptr you can never get it out and use it in a more appropriate smart pointer. You should at least be giving the client the choice.
Noah Roberts
I can't agree. One smart pointer is enough for all your programs. Efficiency is needed to this extent in 0.00001% of the cases, and then it will all be handled differently.
Pavel Radzivilovsky
This has nothing to do with efficiency. If one smart pointer is enough, why do you think the standard is adding 2 of them? Shared semantics is quite often not what is desired.
Noah Roberts
Its not just a question of efficiency, but also of clarity. By using `shared_ptr`, you are pretending that nobody owns that container when that is clearly not the case. Now, I'm left wondering what I'm allowed to do with the container, and who else might notice the changes I make. `unique_ptr` [or, in today's standard `auto_ptr`] make it clear that there's only one instance of this container floating around unless I chose to move it into a `shared_ptr` myself.
Dennis Zickefoose
Of course, given that the original question, while vague, seems to suggest ownership of the container isn't being transfered out of the routine, a `shared_ptr` would be appropriate. Should this method of passing things around be chosen.
Dennis Zickefoose
I agree with Noah, it's not a matter of efficiency, it's a matter of semantics. Sharing an object between two parts of the code leads to subtle bugs, thus by default you usually don't share. Why not simply returning a copy ? With RVO and move semantics it's actually cheap.
Matthieu M.
A: 

I think you have to better describe your problem. Simply, to return a collection, I would say, use a template that returns an iterator. But if you are talking about client code, i.e. the app will be separated into a few parts and they might be compiled separately, I would say the only portable way is to use a pointer to an array. But, what do you mean by remote? If it means a seperate machine, then you need some form of serialization like Boost::Serialization or Protobuf.

Gianni
+4  A: 

The iterator way is the way you really want. Why? Because it allows the client to stick this data into whatever they need to. As you are aware, you're already having trouble deciding how to stick data on the end of the container because there are different ways. With an OutputIterator though you don't have to worry about it. Assign and move forward.

Hell, the user of your function might want to stick the data in a string and if you use the iterator method this is trivial.

Noah Roberts
A: 

I think I have finally understood your problem, I'll just rephrase it:

  • You have a collection of objects
  • You wish your client to have access to the objects, without knowing the details of implementation
  • The collection and the client might be on different machines (you thus have a way to put it in a message)

I would simply return a copy of the collection, suitably wrapped to abstract away the actual implementation.

For example, a Collection class, with begin and end members to access custom iterators. The class is instantiated with the serialized form of the collection, and deserialize it (lazily or not). It's up to your client to use the iterators to stash the data in the collection she wishes.

Matthieu M.