For example, let's say I want to pass the values (1,2),(2,3),(3,4), etc. into a function and have it return a list of numbers, whatever they may be, i.e. 1, 3, 5, 3, 6 after some operations. What is the best way to achieve this result in C++? After moving from python it seems a lot more difficult to do it here, any help?
Asked
Active
Viewed 519 times
3 Answers
3
In general, you would use the std::vector
container and its method push_back
. You can then return the vector (return it by value, don't bother allocating it dynamically since your compiler probably supports move-semantics).
std::vector<int> func(
const std::tuple<int, int>& a, const std::tuple <int, int>& b)
{
std::vector<int> ret;
ret.push_back(...);
ret.push_back(...);
return ret;
}

Paul Manta
- 30,618
- 31
- 128
- 208
-
I keep getting a "C++ forbids declaration of tuple with no type" error whenever I try to implement this. Any ideas? – Bob John Aug 12 '12 at 10:45
-
the function has a collection of tuples as input and not just 2 tuples, returning vectors is very inefficient and most often justifies the less readability. – SkyWalker Aug 12 '12 at 10:46
-
you are missing an include try `#include
` but this solution is in general not very elegant. Check my comment above. – SkyWalker Aug 12 '12 at 10:47 -
1@GiovanniAzua Returning vectors is no longer inefficient thanks to C++11 and move semantics. – Paul Manta Aug 12 '12 at 11:08
-
@PaulManta good, but always double check using valgrind or more paranoically using a performance test case that this is the case so are not left with a 10x slower code without noticing at testing stage. Still your input design is not really general, only 2 tuples? – SkyWalker Aug 12 '12 at 11:17
-
-
@PaulManta OP is 'I want to pass the values (1,2),(2,3),(3,4), etc' I see variable number of inputs and your function only accepts 2 tuples ... – SkyWalker Aug 12 '12 at 11:43
-
2
I'm not saying this is the best way but I think it is pretty good, also from the memory-copying prospective, note I avoid returning a vector
(expensive since it invokes the operator=
implicitly):
#include <vector>
using namespace std;
/**
* Meaningful example: takes a vector of tuples (pairs) values_in and returns in
* values_out the second elements of the tuple whose first element is less than 5
*/
void less_than_5(const vector<pair<int, int> >& values_in, vector<int>& values_out) {
// clean up the values_out
values_out.clear();
// do something with values_in
for (vector<pair<int, int> >::iterator iter = values_in.begin(); iter != values_in.end(); ++iter) {
if (iter->first < 5) {
values_out.push_back(iter->second);
}
}
// clean up the values_out (again just to be consistent :))
values_out.clear();
// do something with values_in (equivalent loop)
for (int i = 0; i < values_in.size(); ++i) {
if (values_in[i].first < 5) {
values_out.push_back(values_in[i].second);
}
}
// at this point values_out contains all second elements from values_in tuples whose
// first is less than 5
}

SkyWalker
- 13,729
- 18
- 91
- 187
-
Can you explain how `vector
>::iterator iter = values_in.begin();` works? – Bob John Aug 12 '12 at 10:38 -
this is by itself a brand new question :) but it is conceptually simple. Every collection has an iterator (to iterate over the elements of that collection) and you have access to the begin() and end() elements of the collection. To get hold of the iterator type you simple use the traits on that type, in this case `vector
>::iterator` but it applies to any collection e.g. `map – SkyWalker Aug 12 '12 at 10:43>::iterator` -
OK, so, if I understand correctly, the way you've implemented the for-loop is by starting with the first pair of numbers in the vector and ending with the last pair of numbers? Why did you write iter != instead of ==? – Bob John Aug 12 '12 at 10:48
-
Exactly. The loop goes on `iter != values_in.end()` while the current element pointed to by `iter` is not the end() 'marker' element. – SkyWalker Aug 12 '12 at 10:49
-
You want the loop to end when you get to the end of the container and not before, so `!=` is the right test. – jahhaj Aug 12 '12 at 10:49
-
I gave you the most complete, efficient and clean solution and I get no positive votes ... this is an unfair world :D – SkyWalker Aug 12 '12 at 10:51
-
Positive vote and best answer from me, thank you for your explanation. If I have further questions, I hope you are prepared to answer! :) – Bob John Aug 12 '12 at 10:53
-
cool, if you have questions shoot away :) I recommend you create a small test case, compile, run it and get familiar with the constructs. – SkyWalker Aug 12 '12 at 10:57
-
2Returning a vector does not invoke `operator=`. In C++11, it will either invoke the move constructor or do NRVO. In C++98, it will either invoke the copy constructor or do NRVO. And every major compiler has been implementing NRVO for many years. – fredoverflow Aug 12 '12 at 11:01
-
interesting ... is this something specific to the MSVC compiler only? – SkyWalker Aug 12 '12 at 11:03
-
2NRVO is not tied to a specific compiler. And move semantics are part of every compiler claiming to support C++11 at least partially, because it is very easy to implement and has far reaching performance benefits. – fredoverflow Aug 12 '12 at 11:06
-
OK good to know. I didn't enjoy sacrificing readability for the sake of performance but working on a High Performance project didnt want to risk performance penalties resulting from using inefficient function signatures. Now I know I can rely on NRVO ... I will double-check that the compilers I use offer this and most importantly double-check with valgrind I am not being penalized performance-wise because of returning objects 'by value' – SkyWalker Aug 12 '12 at 11:09
-
Note that the standard does not guarantee NRVO, but it *does* guarantee move semantics. What compiler are you using, exactly? – fredoverflow Aug 12 '12 at 11:10
-
-
2Can it compile `int&& i = 42;`? If it can, it supports rvalue references, which means it should also support move semantics and perfect forwarding. – fredoverflow Aug 12 '12 at 11:19
-
Excellent! I will check this, since it will improve readability of some of my project functions e.g. move matrix type multiply function from `a.multiply(const matrix &b, matrix& c)` to use instead `c = a*b` and `matrix matrix::operator*(const matrix& b) const`. I learned something too :) – SkyWalker Aug 12 '12 at 11:21
-
What is the internal representation of `matrix`? If it's just an array like `float m_matrix[16];` then move semantics does not gain you anything. On the other hand, if it's a pointer to something on the heap, move semantics can speed things up dramatically. Did you write `matrix` yourself? If so, you must provide your own special move operations. Note that NRVO is orthogonal to move semantics; even returning a matrix with a `float m_matrix[16];` member can be optimized optimally with NRVO. – fredoverflow Aug 12 '12 at 11:25
-
matrix is my own, very tailored to the use-cases of the specific algorithm. matrix data is `T* __restrict m_data` and is allocated in the heap and page-aligned. – SkyWalker Aug 12 '12 at 11:27
-
I really like the concept NRVO and would not hessitate to move to it BUT the contract is not so clear as while using copy constructor or `operator=` where you actually take control and ensure the proper functioning. I would be very concern to see lot of useless memory copying just because of e.g. changing compiler though currently I only use Intel Compiler and GNU compilers (latest versions) – SkyWalker Aug 12 '12 at 11:30
-
@GiovanniAzua Again, C++11 *guarantees* that automatic objects will be moved out of functions, which results in just a couple of machine instructions. All you need to do is provide the special move operations `matrix(matrix&&)` and `matrix& operator=(matrix&&)`. – fredoverflow Aug 12 '12 at 14:45
0
void function(const std::vector<std::pair<int,int>> &pairs,
std::vector<int> &output) {
/* ... */
}

perreal
- 94,503
- 21
- 155
- 181
-
Can you please clarify why pairs and output are references in this snippet? – Bob John Aug 12 '12 at 10:28
-
1
-
@GiovanniAzua [Move semantics](http://stackoverflow.com/questions/3106110/) make returning a vector very cheap. – fredoverflow Aug 12 '12 at 11:03
-
@FredOverflow you are commenting in the wrong context. We are discussing input parameters, input parameter copy vs pass by reference, here the copying is real if you don't use references. – SkyWalker Aug 12 '12 at 11:05
-
-
@FredOverflow The OP comment is 'Can you please clarify why pairs and output are references in this snippet?' your comment talking about return values is off topic w.r.t. the OP comment. – SkyWalker Aug 12 '12 at 11:10