Но есть разная дурка, которая аффектит рантайм, но проходит мимо всех ворнингов (иногда это ловят всякие clang-tidy и прочие PVS студии).
Вот канонический пример:
#include<iostream>
#include <map>
#include <vector>
#include <string>
using namespace std;
using Vec = vector<string>;
void f(pair<string, Vec>&& arg) {
for (const auto& v: arg.second) {
puts(v.c_str());
}
}
int main(){
auto m = map<string, Vec>{
{"first", {"1","2"}},
{"second", {"3","4","5"}},
};
for (auto&& p: m) {
f(std::move(p));
}
}
Мы создаем мапу (она будет создана в компайл тайме), а потом все объекты из нее эффективно муваются.
Но если мы внимательно посмотрим в исхродный код, то найдем там вот такое:
call memcpy@PLT
Я прошу прощения...? Какое копирование?! Где?
И вообще весь блок выглядит подозрительно похоже на конструктор копирования:
.LBB1_84:
mov qword ptr [rsp + 56], r13
mov r14, qword ptr [rbx + 32]
mov rbp, qword ptr [rbx + 40]
cmp rbp, 16
jb .LBB1_87
lea r15, [rbp + 1]
mov rdi, r15
call operator new(unsigned long)@PLT
mov qword ptr [rsp + 56], rax
mov qword ptr [rsp + 72], rbp
jmp .LBB1_89
.LBB1_87:
test rbp, rbp
je .LBB1_106
lea r15, [rbp + 1]
mov rax, r13
.LBB1_89:
mov rdi, rax
mov rsi, r14
mov rdx, r15
call memcpy@PLT
.LBB1_90:
mov qword ptr [rsp + 64], rbp
mov r14, qword ptr [rbx + 64]
mov qword ptr [rsp + 88], r14
movups xmm0, xmmword ptr [rbx + 72]
mov r15, qword ptr [rbx + 72]
movups xmmword ptr [rsp + 96], xmm0
xorps xmm0, xmm0
movups xmmword ptr [rbx + 64], xmm0
mov qword ptr [rbx + 80], 0
cmp r14, r15
je .LBB1_98
Не буду тут показывать, но, если провести перфоманс тесты, мы тоже увидим, что тут все тормозит.
И если детально разобраться: так и есть - это конструктор копирования.
Проблема вот в этой функции:
void f(pair<string, Vec>&& arg)
Если поменять объявление этой функции на
void f(pair<const string, Vec>&& arg) {то этот блок строк на 70 машинного кода уйдет, а перфоманс выровняется.
Почему так? Если посмотреть на cpp reference, то мы увидим, что
key_type Key
mapped_type T
value_type std::pair<const Key, T>
значение в мапе содержит константный ключ. А конвертировать из структуры с константным ключем в структуру с неконстантным ключом.... Это копирование!...
И ни одного ворнинга! Мой же ты любимый С++.