preferable way to return a vector?

Nov 28, 2011 at 1:29am
Hi, all -

This isn't so much a "how to" question, as a matter of "good" programming technique.

I have a class that produces a series of values when I call its main routine. My programming convention so far has been to return computed values through a get() function. If I adhere to my convention, this particular get() would need to return a vector by reference (if this is even possible).

One alternative is to have the get() return one element at a time, but this is less than desirable. I'd much rather return the entire vector as a unit.

What do you think: should I ignore my convention and return the values through a vector parameter in the main function? Or, is there some clever way of doing this with a get()? I want the calling program to retain full control of the memory management of the vector.

Thanks for any suggestions.
Nov 28, 2011 at 1:35am
You could make the get() function return a const reference.
Nov 28, 2011 at 1:38am
Can you give me a little more detail on this, please?
Nov 28, 2011 at 1:52am
If I understand it correctly you have a class that contains a vector and you want to access that vector from outside.

By returning a const reference you allow the vector to be accessed from outside without having to copy the vector. The vector is protected from changes outside the class because get() returns a const reference.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <vector>
#include <iostream>

struct A
{
	A(){v.push_back(3);v.push_back(5);}
	const std::vector<int>& get() const {return v;}
	std::vector<int> v;
};

int main()
{
	A a;
	const std::vector<int>& v = a.get();
	for (std::size_t i = 0; i < v.size(); i++)
	{
		std::cout << v[i] << std::endl;
	}
}
Nov 28, 2011 at 1:54am
For efficiency, I would normally populate a reference to the std::vector passed as a parameter. However, the new C++ standard (C++11) makes returning a locally created vector very efficient, so now it is just as efficient to return a locally created vector.
Last edited on Nov 28, 2011 at 2:06am
Nov 28, 2011 at 2:07am
Thanks for the suggestions. I'm still relatively new to the C++ "culture," if you will. Which of the above suggestions is preferable in your minds for a production application? Ultimate performance isn't a priority; I'd prefer to focus on code clarity.
Nov 28, 2011 at 2:20am
I think Galik's suggestion is good if you create the vector inside the function itself. In this case you can return by value and it will not need to make any expensive copies (assuming an up to date compiler). You can't return a reference anyway because the vector will get destroyed after the function ends, leaving an invalid reference.

Returning a (const) reference makes more sense when the vector is stored somewhere so the vector stays alive after the function has returned. If you returned the vector by value in this case a copy can't normally be avoided.
Nov 28, 2011 at 3:09am
OK, so in this case, the vector and its elements are created in the containing class. I'd like the get() call to the included class to populate the existing elements, but not create (push_back) any new ones. Does it make the most sense, then, to just pass the vector by reference to the get()?
Nov 28, 2011 at 3:50am
If you want them to be able to "see" the vector but not modify it, then just return a const reference.
Nov 28, 2011 at 4:06am
Oh, I can tell I'm not doing a very good job of explaining this.

Class A contains an object of Class B.

Class B produces a series of outputs, which I'd like to get all at once with a get() call.

I'd like the output produced by B::get() to go into a pre-existing structure, so B does indeed need to modify the contents of the vector.

I'm getting the impression that the most straightforward way to do this is:

1
2
3
4
5
6
7
void DemodNyq::get(vector<int32_t>& v)
{
	for (unsigned int i = 0; i < v.size(); ++i)
	{
		v.at(i) = cells.at(i)->get();
	}
}


The only drawback to this is that B's get() function now behaves a little differently from all the others, in that the returned stuff is through a parameter, not the return argument, but I can live with this if it's the least of all evils.
Nov 28, 2011 at 5:13am
The main thing to worry about is who owns the vector:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// If the vector is owned by the class then you can return
// a const reference to it (assuming you don't want to modify it) 
class A
{
	std::vector<int> v;
	
public:
	const std::vector<int>& getV() { return v; }
};

// If the vector is created by the function itself then you can
// simply return it by value (assuming C++11). 
// However if your compiler is not C++11 ready then you may want to
// pass in a reference.
class B
{
public:
	// C++11 efficient
	std::vector<int> getV() { std::vector<int> v; /* populate v */ return v; }

	// C++03 efficient
	void getV(std::vector& v) { v.clear(); /* populate v */ }
}

Last edited on Nov 28, 2011 at 5:14am
Nov 28, 2011 at 5:22am
Yeah, in this case, the vector is owned by the containing class, but I want the contained class to modify its contents (though not its size). It appears that the best approach is what we came to in the last few posts. I don't see the need for a clear, since I can just overwrite the contents, or...is that bad practice with vectors? Once created, its size should remain fixed.
Nov 28, 2011 at 6:08am
You don't need the clear().
Nov 28, 2011 at 6:13am
OK, thanks for the help, everyone.
Nov 28, 2011 at 3:05pm

1
2
// C++11 efficient
std::vector<int> getV() { std::vector<int> v; /* populate v */ return v; }


This is also the most efficient approach in C++98 (and C++03), unless you've resurrected a particularly ancient compiler. See: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

In general, best practice is for the code to reflect the semantics: return is to produce a new value, reference/iterator argument is to modify an already-existing value.
Last edited on Nov 28, 2011 at 3:11pm
Nov 28, 2011 at 3:14pm
Hi, Cubbi -

Would your example work if I used it in an assignment statement? In other words:

1
2
3
vector<int> myVector;
// push_back, etc.
myVector = getV();
Nov 28, 2011 at 3:24pm
It would work yes, but I don't think it can avoid a copy in this case.

Your code would work if getV() returned a reference too
Nov 28, 2011 at 3:38pm
mzimmers:

In case of using the return value as an argument in assignment, myVector becomes the new owner of v's dynamic array, myVector's old dynamic array is deleted. No copies are made (assuming compiler with basic optimization enabled). In C++11 it's called 'move assignment', but it's just a new name and formalism for the long standing existing practice.

In this case it is indeed more efficient to pass by reference: if you're not changing the array size, you're avoiding allocations.
Last edited on Nov 28, 2011 at 3:39pm
Nov 28, 2011 at 4:27pm
I just re-read your earlier post:

In general, best practice is for the code to reflect the semantics: return is to produce a new value, reference/iterator argument is to modify an already-existing value.


I think this is the answer I was looking for. Thanks...good to have you on this forum.
Topic archived. No new replies allowed.