C++ transform参数初始化问题

C++ transform parameter initialization question

我试图将字符串转换为小写并将其存储在使用 std::transformstd::tolower 的另一个变量中。我第一次尝试:

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

但是,lowerStr1什么也没有。用 str1 初始化 lowerStr1 后,我得到了想要的结果。我想知道这背后的直觉。有人可以解释为什么 lowerStr1 在这种情况下应该初始化吗?

lowerStr1为空,std::transform不会向其中插入元素。

std::transform applies the given function to a range and stores the result in another range, beginning at d_first.

您可以使用 std::back_inserter, which constructs a std::back_insert_iterator,它会在容器上调用 push_back() 来插入元素。

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

或者预先让lowerStr1包含5个元素

string lowerStr1(5, '[=11=]');
transform(str1.begin(), str1.end(), lowerStr1.begin(), ::tolower);

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

Could someone explain why lowerStr1 should be initialized in this case?

那是因为你像上面那样提前初始化了包含5个元素的lowerStr1。事实上,初始化元素的值是多少并不重要。

这是因为您对 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() 笼统地说,给你一个指向空字符串的指针。因此,写入该指针并雪上加霜,递增并继续写入,会导致未定义的行为、内存损坏和崩溃的可能性。

您不会通过获取指向空字符串的指针然后在该指针中涂鸦来向空字符串添加内容。有几种方法可以正确地做到这一点,使用 push_back() 或 insert() 方法。您还可以使用执行此操作的迭代器,例如 std::back_insert_iterator,它可以与 std::transform.

一起使用

通用算法不会更改容器的大小。 您需要使用以特殊方式实现 operator= 的迭代器适配器,以便它实际插入元素。 因此,您可以使用 back_inserter(lowerStr1) 来确保 lowerStr1trasform() 一样进行分配。

#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;
}