Who pays for

Given:

void foo(std::vector<int> v); void bar() { std::vector<int> v = ...; // many items foo(v); } 

What will the profiling tool display as a hot path? Will it be a copy constructor std::vector<T> , runtime or operating system? I remember at school (I'm not a C ++ developer, I just work with some) that this will copy v , and this may take some time. I know the signature is like:

 void foo(const std::vector<int>& v); 

avoids this potentially costly copy operation.

+5
source share
4 answers

Copying std::vector<T> by value does, perhaps, three things:

  • The memory manager (C ++ runtime or custom allocator) looks for an available block of memory for the new vector in its entries. If he finds him, he will go to step No. 3.
  • The memory manager (C ++ runtime or user allocator) requests more memory from the OS. This call itself is relatively cheap (as much as syscall can be), because the OS gives memory in lazy mode - the actual distribution occurs when you first write to the requested VM page.
  • The code (application) generated by the compiler does new in place with a copy of c-tor for each element in the new vector, if T not trivially copied. Otherwise, memcpy() or optimized vectorization (in sse ) is called. Shortly before a new memory is written, if it was obtained from the OS at No. 2, the OS will need to actually assign a new VM page that can initiate access to RAM (hardware), TLB search (hardware + OS) swapping in / out (OS).

In your specific example, T trivially copied, so the worst overhead will be C++ to search in the runtime block <+27> syscall + memcpy() .

+5
source

The decision to take an argument by value in comparison with a reference to const should consider what the function plans to do with the value. If a function only pays when reading from an existing value, then a const reference is the most suitable option. If the called function would make a copy of the mentioned object as part of its implementation, then passing by value can be faster, because the caller can move the argument construction, if that 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 } 
+2
source

You can expect the copy constructor std::vector<int> be created.

A smart compiler is allowed to optimize a copy of the value if there are no side effects in its actions. Moreover, if the function definition is marked inline , then a copy of the value will not be accepted if the compiler executes your request (this is not necessary).

It is best to direct v to a const link. This not only eliminates the copy of the value, but also means that the called function cannot modify the passed argument.

+1
source

The compiler should only emit code that acts as-if , it runs your code, that is, the observed behavior is the same.

The likely access point should be either the assignment operator in bar , as you need to create the original vector or copy constructor.

In your example, the compiler can rewrite it differently if it can be explained that v is never used in bar anymore, so it can implement the call foo(v); like foo(std::move(v)) (e.g. @MSalters already mentioned). This leaves v as a dead object in bar() , which is then destroyed.

Alternatively, the compiler can simply create a vector in the call stack and save the call to the destructor itself, effectively making a free call by default.

+1
source

All Articles