Вопрос инициализации параметра преобразования C ++ - PullRequest
1 голос
/ 21 февраля 2020

Я пытался преобразовать строку в нижний регистр и сохранить ее в другой переменной, используя std::transform и std::tolower. Сначала я попробовал:

string str1("Hello");
string lowerStr1;
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);
cout << lowerStr1 << endl;

Но, lowerStr1 ничего не содержал. После инициализации lowerStr1 с str1 я получил желаемый результат. Я хочу знать интуицию, стоящую за этим. Может ли кто-нибудь объяснить, почему lowerStr1 следует инициализировать в этом случае?

Ответы [ 3 ]

1 голос
/ 21 февраля 2020

lowerStr1 пусто, и std::transform не будет вставлять в него элементы.

std::transform применяет данную функцию к диапазону и сохраняет результат в другом диапазоне, начиная с d_first.

. Вы можете использовать std::back_inserter, который создает std::back_insert_iterator, что вызовет push_back() на контейнере для вставки элементов.

transform(str1.begin(), str1.end(), back_inserter(lowerStr1), ::tolower);

или сделать lowerStr1, содержащий 5 элементов заранее.

string lowerStr1(5, '\0');
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);

или

string lowerStr1;
lowerStr1.resize(5);
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);

Может кто-нибудь объяснить, почему lowerStr1 должна быть инициализирована в этом случае?

Это потому, что вы инициализируете lowerStr1, содержащую 5 элементов заранее, как указано выше. Какое значение инициализированных элементов на самом деле не имеет значения.

0 голосов
/ 21 февраля 2020

Generi c алгоритмы не изменят размер контейнеров. Вам нужно использовать адаптер итератора, который реализует operator= особым образом, чтобы он фактически вставлял элементы. Поэтому вы можете использовать back_inserter(lowerStr1), чтобы убедиться, что lowerStr1 расширяется при выполнении trasform() назначений.

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;

int main() {
  string str1("Hello");
  string lowerStr1;
  transform(str1.begin(), str1.end(), std::back_inserter(lowerStr1), ::tolower);
  cout << lowerStr1 << endl;
}

0 голосов
/ 21 февраля 2020

Это потому, что ваш вызов std::transform логически эквивалентен следующему коду:

auto b=str1.begin();
auto e=str1.end();
auto p=lowerStr1.begin();

while (b != e)
{
       *p=tolower(*b);
       ++b;
       ++e;
}

Но lowerStr1 - это совершенно пустая строка. lowerStr1.begin() дает вам, грубо говоря, указатель на пустую строку. Таким образом, запись в этот указатель и добавление оскорбления к травме, увеличение его и продолжение записи в него приводит к неопределенному поведению, повреждению памяти и нетривиальной возможности взлома sh.

. не добавлять содержимое в пустую строку, захватывая указатель на нее, а затем вписываясь в этот указатель. Есть несколько способов сделать это правильно, используя методы push_back () или insert (). Вы также можете использовать итератор, который делает это, например std :: back_insert_iterator , который можно использовать с std::transform.

...