Reputation: 190976
Given:
void foo(std::vector<int> v);
void bar()
{
std::vector<int> v = ...; // many items
foo(v);
}
What in a profiling tool would show as the hot path? Would it be the std::vector<T>
's copy constructor, the runtime or the operating system? I remember in school (I'm not a C++ dev, just work with some) that this will copy v
and that can take time. I do know that a signature like:
void foo(const std::vector<int>& v);
avoids this potentially costly copy operation.
Upvotes: 5
Views: 223
Reputation: 18864
Copying std::vector<T>
by value does, potentially, three things:
new
with copy c-tor for each element in the new vector if T
is not trivially copy-constructible. Otherwise, memcpy()
or it's optimized vectorized (in sse
sense) counterpart is called. Just before the first time the new memory is written, if it was acquired from the OS in #2, the OS will need to actually allocate the new VM page and that may trigger RAM access (hardware), TLB lookup (hardware + OS) swapping in/out (OS).In your specific example T
is trivially copy-constructible so the worst case overhead would be C++
runtime memory block lookup + sbrk()
syscall + memcpy()
call.
Upvotes: 5
Reputation: 1871
The decision to take an argument by value versus by const reference should take into account what the function plans on doing with the value. If the function only plans on reading from the existing value, then a const reference is the most efficient choice. If the called function would have made a copy of the referenced object as part of its implementation, then passing by value has a potential to be faster as the caller can move construct the argument if it makes sense, and remove the need for a copy.
void foo(std::vector<int> v);
void bar()
{
std::vector<int> v = ...; // many items
foo(std::move(v)); // no copy needed here
}
Upvotes: 2
Reputation: 16109
The compiler only have to emit code that acts as-if
it runs your code, that is the observable behavior is the same.
The likely hotspot should be either the assignment operator in bar
as you need to create the original vector or a copy constructor.
In your example the compiler can rewrite it in different ways, if it can reason out that v
is never used in bar
again so it might implement the call foo(v);
as foo(std::move(v))
(like @MSalters already mentioned).
This leaves v
as a dead object in bar()
which is then destroyed.
Alternatively the compiler might just create the vector
on the call stack and save itself a call to the destructor, effectively making the call-by-value free.
Upvotes: 1
Reputation: 234785
You can expect the copy constructor of std::vector<int>
to be called.
A clever compiler is permitted to optimise out the value copy if there are absolutely no side effects in its doing to. Futhermore, if the function definition is marked inline
then a value copy will not be taken if the compiler honours your request (it doesn't have to).
You're best bet is indeed to pass v
by const
reference. Not only does this obviate the value copy, but it also means that the function being called cannot modify the argument passed.
Upvotes: 1