Вероятно, вы видите эффект оптимизации маленькой / короткой строки .Чтобы избежать ненужных выделений для каждой крошечной строки, многие реализации std::string
включают небольшой массив фиксированного размера для хранения небольших строк без необходимости new
(этот массив обычно повторно использует некоторые другие члены, которые не нужны при динамическом выделениине использовался, поэтому он потребляет мало или вообще никакой дополнительной памяти для его предоставления, как для малых, так и для больших string
с), и эти строки не получают выгоды от std::move
(но они малы, так что это нормально),Большие строки потребуют динамического выделения и передадут указатель, как вы ожидаете.
Просто для демонстрации, этот код на g++
:
void move_test(std::string&& s) {
std::string s2 = std::move(s);
std::cout << "; After move: " << std::hex << reinterpret_cast<uintptr_t>(s2.data()) << std::endl;
}
int main()
{
std::string sbase;
for (size_t len=0; len < 32; ++len) {
std::string s1 = sbase;
std::cout << "Length " << len << " - Before move: " << std::hex << reinterpret_cast<uintptr_t>(s1.data());
move_test(std::move(s1));
sbase += 'a';
}
}
Попробуйте онлайн!
создает высокие (стековые) адреса, которые изменяются при построении перемещения на длины 15 или менее (предположительно, зависят от размера указателя архитектуры), но переключаются на низкие (куча) адреса, которые остаются неизменными после построения перемещения после того, как выдлина удара 16 или выше (переключатель на 16, а не на 17, потому что он NUL
- определяет строки, поскольку C ++ 11 и выше требуют этого).
Чтобы быть на 100% ясным: этоэто деталь реализации.Ни одна часть спецификации C ++ не требует такого поведения, поэтому вам не следует полагаться на то, что оно вообще происходит, и когда оно происходит, вы не должны полагаться на то, что оно происходит для определенных длин строк.