首页 > 解决方案 > 嵌套的 std::transform 效率低吗?

问题描述

如果我有std::string

std::string s{"hello"};

和一个就地修改它的循环,如下所示:

for (auto &c: s)
  c = std::toupper(c);

我可以用等效的替换它transform

std::transform(s.begin(), s.end(), s.begin(),
               [](unsigned char c) -> unsigned char 
               { return std::toupper(c); });

并且这些片段生成相同的程序集。他们也有类似的表现

但是,如果我有std::vector<std::string>

std::vector<std::string> v {"hello", "how", "are", "you"};

并像这样就地修改它:

for (auto & s : v)
  for (auto &c: s)
    c = std::toupper(c);

等效变换应该是:

std::transform(std::begin(v), std::end(v), std::begin(v),
  [](auto s) {
    std::transform(std::begin(s), std::end(s), std::begin(s), 
      [](unsigned char c) -> unsigned char { return std::toupper(c); });
    return s;
});

但是,该transform版本生成了一半以上的程序集,并且相应地表现不佳,这让我感到惊讶。

在这种情况下不是std::transform零成本抽象,还是我只是使用不正确?

标签: c++performancestl-algorithm

解决方案


通过引用传递和返回所有内容。否则,您制作字符串的多个副本。注意变化:[](auto& s) -> std::string& {

std::transform(std::begin(v), std::end(v), std::begin(v),
  [](auto& s) -> std::string& {
    std::transform(std::begin(s), std::end(s), std::begin(s), 
      [](unsigned char c) -> unsigned char { return std::toupper(c); });
    return s;
});

我在您的链接中添加了两个新的 quickbench 功能。一种将输入字符串作为引用传递。另一个也通过引用返回。那是:

static void Transform2(benchmark::State& state) {
  // Code before the loop is not measured

  std::vector<std::string> v {"hello", "how", "are", "you"};
  for (auto _ : state) {
    std::transform(std::begin(v), std::end(v), std::begin(v),
    [](auto& s) {
      std::transform(std::begin(s), std::end(s), std::begin(s), 
        [](unsigned char c) -> unsigned char { return std::toupper(c); });
      return s;
    });

  }
}
BENCHMARK(Transform2);


static void Transform3(benchmark::State& state) {
  // Code before the loop is not measured

  std::vector<std::string> v {"hello", "how", "are", "you"};
  for (auto _ : state) {
    std::transform(std::begin(v), std::end(v), std::begin(v),
    [](auto& s) -> std::string& {
      std::transform(std::begin(s), std::end(s), std::begin(s), 
        [](unsigned char c) -> unsigned char { return std::toupper(c); });
      return s;
    });

  }
}
BENCHMARK(Transform3);

根据我在运行基准测试时的幸运程度,Transform3 的性能几乎(有时甚至等于)InPlace 测试实现。

在此处输入图像描述


推荐阅读