More Functions
Consider wanting to write a vector that takes one vector as input and returns a new one.
We can imagine:
std::vector<double> f(const std::vector<double>& v_in) {
std::vector<double> v_out;
// do stuff to fill v_out based on v_in
return v_out;
}
This looks like it is returning v_out
by value and that when we do:
auto v_new = f(v_old);
that we need to make a copy. But C++ instead provides move
semantics—this means that instead of copying the entire contents
of the local v_out
to the vector in the caller v_new
it simply
moves the data by setting the pointer to the data region in v_new
to the data region in v_out
before v_out
is destroyed.
A second method is to pass it through the argument list as a reference:
void f(const std::vector<double>& v_in, std::vector<double>& v_out) {
// fill v_out based on v_in
}
Then we can do:
std::vector<double> v_old{};
std::vector<double> v_new{};
f(v_old, v_new);
Danger
What about returning a reference? We might think that we could do:
std::vector<double>& f(const std::vector<double>& v_in) {
std::vector<double> v_out;
// do stuff to fill v_out based on v_in
return v_out;
}
The problem here is that v_out
is destroyed at the end of the function
f
, so the reference will be to something that no longer exists.
This is not allowed—we cannot return a reference to a local
variable.
Let’s play with this:
#include <iostream>
#include <vector>
std::vector<double> f1(const std::vector<double>& v_in) {
std::vector<double> v_out;
for (auto e : v_in) {
v_out.push_back(2.0 * e);
}
return v_out;
}
void f2(const std::vector<double>& v_in, std::vector<double>& v_out) {
v_out.clear();
for (auto e : v_in) {
v_out.push_back(2.0 * e);
}
}
std::vector<double>& f3(const std::vector<double>& v_in) {
std::vector<double> v_out;
for (auto e : v_in) {
v_out.push_back(2.0 * e);
}
return v_out;
}
int main() {
std::vector<double> v_old{0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
auto v_new1 = f1(v_old);
for (auto e : v_new1) {
std::cout << e << " ";
}
std::cout << std::endl;
std::vector<double> v_new2{};
f2(v_old, v_new2);
for (auto e : v_new2) {
std::cout << e << " ";
}
std::cout << std::endl;
auto v_new3 = f3(v_old);
for (auto e : v_new3) {
std::cout << e << " ";
}
std::cout << std::endl;
}