C++: почему ввод строки не выполняется, а другой нет

Я получил эту проблему от друга

#include <string>
#include <vector>
#include <iostream>

void riddle(std::string input)
{
    auto strings = std::vector<std::string>{};
    strings.push_back(input);
    auto raw = strings[0].c_str();

    strings.emplace_back("dummy");

    std::cout << raw << "\n";
}

int main()
{
    riddle("Hello world of!"); // Why does this print garbage?
    //riddle("Always look at the bright side of life!"); // And why doesn't this?

    std::cin.get();
}

Мое первое наблюдение заключается в том, что riddle() Функция не будет производить мусор, когда количество слов, переданных в input больше 3 слов. Я все еще пытаюсь понять, почему это не так в первом случае, а не во втором. Anyways думал, что это было бы весело поделиться.

2 ответа

Решение

Это неопределенное поведение (UB), означающее, что может произойти все что угодно, включая работающий код. Это UB, потому что emplace_back делает недействительными все указатели на объекты в векторе. Это происходит потому, что вектор может быть перераспределен (что, очевидно, так и есть).

Первый случай UB "не работает" из-за оптимизации коротких строк (sso). Благодаря sso необработанный указатель указывает на память, непосредственно выделенную вектором, которая теряется после перераспределения.

Второй случай UB "работает", потому что текст строки слишком длинный для единого входа и находится в независимом блоке памяти. Во время изменения размера строковый объект перемещается из, перемещая владельца блока памяти текста во вновь созданный строковый объект. Поскольку блок памяти просто меняет владельца, он остается в силе после emplace_back,

std::string::c_str():

Возвращенный указатель может быть признан недействительным при последующих вызовах других функций-членов, которые изменяют объект.


std::vector::emplace_back:

Если происходит перераспределение, все содержащиеся элементы модифицируются.


Поскольку нет способа узнать, является ли vector перераспределение произойдет при вызове emplace_back Вы должны предположить, что последующее использование более раннего возвращаемого значения из string::c_str() приводит к неопределенному поведению.

Поскольку неопределенное поведение - неопределенное - может произойти все что угодно. Следовательно, может показаться, что ваш код работает или не работает. В любом случае это ошибка.

Другие вопросы по тегам