Объединение std :: string и int приводит к сдвигу. Зачем? - PullRequest
1 голос
/ 06 мая 2020

Сегодня я был удивлен, когда попытался объединить std::string с int. Рассмотрим следующий MWE:

#include <iostream>
#include <string>

void print(const std::string& text)
{
    std::cout << "The string is: " << text << ".\n";
}

int main()
{
    print("iteration_" + 1);

    return 0;
}

Вместо печати

The string is: iteration_1.

, чего я ожидал, он печатает

The string is: teration_.

Что именно происходит в фоновом режиме? Преобразуется ли строка по какой-либо причине в char[] или что-то в этом роде? Документация по оператора + не перечисляет ни одного с std::string и int.

И как правильно объединить std::string с числом? Мне действительно нужно бросить их оба в std::stringstream или преобразовать число в std::string явно с std::to_string()?

Ответы [ 5 ]

2 голосов
/ 06 мая 2020

"iteration_" не std::string, а const char[]. Которая распадается на const char*, а "iteration_" + 1 просто выполняет арифметику указателя c и перемещает указатель, указывающий на следующий char (т.е. 't'), тогда вы получаете строку в стиле c "teration_".

Вы можете использовать std::to_string, чтобы преобразовать int в std::string, а затем объединить их. например,

print("iteration_" + std::to_string(1));

В этом случае вызывается std :: operator + (std :: basic_string) , и 1-й аргумент "iteration_" неявно преобразуется в std::string, а затем передается в operator+, затем объединенный std::string передается в print.

LIVE

2 голосов
/ 06 мая 2020

Преобразуется ли по какой-то причине строка в char []

На самом деле все наоборот. "iteration_" - это char[11], которое распадается на const char*, когда вы добавляете 1. При увеличении указателя на единицу он указывает на следующий символ в строке. Затем это используется для создания временного std::string, содержащего все символы, кроме первого.

Документация, на которую вы ссылаетесь, предназначена для operator+ из std::string, но для ее использования вам сначала понадобится std::string.

2 голосов
/ 06 мая 2020

Эта строка является проблемой:

print("iteration_" + 1);

Строковый литерал распадается на char*. Вы добавляете 1 к этому char*, перемещая его к следующему символу.

Если вы хотите добавить строку "1" в конец вашего литерала, довольно простой способ - передать строковый литерал в конструктор std::string и вручную преобразовать 1 в строку. Например:

print(std::string("iteration_") + std::to_string(1));
1 голос
/ 06 мая 2020

Выражение "iteration_" + 1 - это const char[11] литерал, добавленный к int 1.

В этом выражении "iteration_" распадается на const char* указатель на первый элемент массива. Затем + 1 занимает место в арифметике указателя c этого указателя. Все выражение оценивается как тип const char* (указывает на первый t), который является допустимым вводом с завершающим NUL для конструктора std::string! (Анонимный временный std::string привязывает к параметру функции const std::string&.)

Это полностью допустимый C ++ и иногда может быть использован с пользой.

Если вы хотите рассматривать + как объединение, тогда

print("iteration_" + std::to_string(1));

будет односторонним.

1 голос
/ 06 мая 2020

Если вы попытаетесь использовать следующее:

std::string str = "iteration" + 1;

компилятор выдаст предупреждение:

предупреждение: добавление 'int' к строке не добавляется к строке [-Wstring-plus-int]

Это потому, что вы увеличиваете указатель на строку «итерация» на 1, что означает, что теперь строка «терации» присваивается переменной str.

Правильный способ конкатенации:

std::string str = "iteration" + std::to_string(1);
...