move it into your function:
// foo() decalaration
void foo(std::vector<int> v);
// usage example
std::vector<int> v {0, 1, 2, 3};
foo(std::move(v));
// v is moved into foo() and invalid now
You may also return this vector from function in the same manner:
// foo() decalaration
std::vector<int> foo(std::vector<int> v) {
return v.push_back(4), std::move(v);
}
// usage example
std::vector<int> v {0, 1, 2, 3};
v = foo(std::move(v));
// now v is {0, 1, 2, 3, 4} and no one were deep copied
But note if you don't move it (call foo(v)
instead of foo(std::move(v))
) then it will be deep copied. Under the hood, parameter v
of foo()
is just constructed by move-constructor.
pass it as reference:
// foo() declaration
void foo(std::vector<int>& v);
But now we have a problem: which reference and cv-qualifiers? Well, in general we have 2 types of references and 4 types of cv-qualifiers, altogether 8 declarations:
void foo(std::vector<int>&);
void foo(std::vector<int> const&);
void foo(std::vector<int> volatile&);
void foo(std::vector<int> const volatile&);
void foo(std::vector<int>&&);
void foo(std::vector<int> const&&);
void foo(std::vector<int> volatile&&);
void foo(std::vector<int> const volatile&&);
Of course, part of them are useless and should be deleted. But nevertheless too much declarations also known as perfect forwarding problem (actually, there were no rvalue-references when it was a problem so the problem was 2 times smaller).
For example, if you want to modify v
you need 2 functions at least:
void foo(std::vector<int>&);
void foo(std::vector<int>&&);
In this case you will be able to call foo()
on lvalue objects:
std::vector<int> v;
foo(v);
as well as on temporary:
foo(std::vector<int>{1, 2, 3, 4, 5});
But how to code just one implementation for different reference types and / or cv-qualifiers? Let me introduce universal references:
template<typename Vector>
void foo(Vector&& v);
Vector&&
is always a reference type and may be deduced into
std::vector<int>&
if you pass lvalue of type std::vector<int>
into foo()
:
std::vector<int> v;
foo(v); // v is lvalue
std::vector<int> const&
if you pass const lvalue of type std::vector<int>
:
std::vector<int> const v;
foo(v); // v is const lvalue
std::vector<int>&&
if you pass rvalue:
foo(std::vector<int>{0, 1, 2}); // v is rvalue
etc...
But in this case you have to check acceptance of type Vector
. But that is another story.