TGViewer
C++: Хроники Дурки🚑 C++: Хроники Дурки🚑 @cpp_durka · 916 subscribers
Post #15 850
Приколько поговорить про гадость, которую можно отловить на этапе компиляции.

Но есть разная дурка, которая аффектит рантайм, но проходит мимо всех ворнингов (иногда это ловят всякие 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>


значение в мапе содержит константный ключ. А конвертировать из структуры с константным ключем в структуру с неконстантным ключом.... Это копирование!...


И ни одного ворнинга! Мой же ты любимый С++.
godbolt.org Compiler Explorer - C++ 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"…
  • 👍 11
  • 😐 5
  • 🔥 3
  • 🗿 2
  • 👌 1
More from @cpp_durka
  1. Sep 8, 2026Мошенники заставили пенсионерку из Москвы переписать квартиру на Rust
  2. Aug 31, 2026Всяко разное болезненное есть в С++, из всего болезненного одно из самых болезненных - это…
  3. Aug 24, 2026Если кто не знаком с библиотекой nlohmann/json - она прекрасна. Мои мысли о том, как должн…
  4. Aug 21, 2026#толькосвоимемы Код взят тут. if (dim == 0) idx_dim = i0; else if (dim == 1) idx_dim = i1;…
  5. Aug 17, 2026Ладно, искать баги в компиляторах весело, но недостаточно. Давайте поиграемся в чуть более…
  6. Aug 10, 2026Ладно, разумеется прошлый пост был набросом. Никогда не обновляйте компиляторы без очень с…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →