【问题标题】:Under what circumstances should you prefer to write to cout using std::copy?在什么情况下你应该更喜欢使用 std::copy 写入 cout?
【发布时间】:2020-01-27 20:25:39
【问题描述】:

我一直在阅读 Scott Meyers 的“Effective STL”,我注意到书中有很多例子,他通过使用std::copy 将元素复制到std::cout 来打印容器的内容。与使用基于范围的for 循环相比,这对我来说很难阅读(也许我只需要习惯它?)

// Given the following
std::vector<int> values = { 1, 2, 3, 4, 5, 6, 7, 8 };

// Print using `std::copy`
std::copy(values.begin(), values.end(), std::ostream_iterator<int>(std::cout, ", "));

// Print using a loop
for (const auto value : values)
{
    std::cout << value << ", ";
}

这篇文章似乎表明使用std::copy 没有显着的性能提升:

is std::copy faster than std::cout for output?

有些人真的觉得std::copy 方法比基于范围的for 循环更具可读性吗?


如果我只想打印一半的值...

std::copy(values.begin(), values.begin() + values.size()/2, std::ostream_iterator<int>(std::cout, ", "));

...但即使那样我也可以这样做:

for (auto it = values.begin(); it != values.begin() + values.size()/2; ++it)
{
    std::cout << *it << ", ";
}

所以我的问题是为什么有人更喜欢std::copy 方法?是否有任何情况可以证明std::copy 确实是更好的选择(或唯一的选择)?

【问题讨论】:

  • 我认为这归结为纯粹基于意见。一般来说,标准算法不是魔法,你总是可以用手写循环替换它们,反之亦然,所以它主要是关于风格和偏好
  • 请注意,您的最后一个示例在使用非随机访问迭代器时存在问题。例如std::list。你不能iter + n,尽管你可以std::next(iter, n),但代价是线性复杂度。
  • 有建议说:“没有原始循环”。如果您同意这一点,那么std::copy 就是解决方案。就个人而言,我不介意微不足道的原始循环,因此我将范围用于整个范围,或者将 copy 用于范围的任何部分。
  • 也就是说,一旦我们得到std::span,我可能会使用span 和远程for。
  • 检查该书的出版时间。它可能完全不了解 C++11,其中包括 auto 变量(至少是那些具有当前含义的变量)和基于范围的 for 循环。

标签: c++ algorithm stl


【解决方案1】:

你可以在cppreference查看可能的实现:

template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, 
              OutputIt d_first)
{
    while (first != last) {
        *d_first++ = *first++;
    }
    return d_first;
}

这并没有什么神奇之处。它实际上只是一个将元素从Input 复制到Output 的循环。当然,它不使用基于范围的 for 循环(它有迭代器而不是容器)。它使用while 而不是for,这只是外观上的区别。

是否有任何情况可以证明 std::copy 确实是更好的选择(或唯一的选择)?

没有。您始终可以手动编写与算法相同的代码。考虑到标准算法不应该比手写代码更好。它们应该和手写代码一样好,而不是更糟。真正的好处是,使用算法可以减少出错的空间,并且更容易识别。写一个复制东西的循环有很多不同的方法,但只有一个std::copy,这实际上有助于阅读代码。

所以这一切都归结为意见......

真的有人觉得 std::copy 方法比基于范围的 for 循环更具可读性吗?

是的,有些人认为应该尽量减少手写循环的使用,以支持算法。但是,幸运的是,可能存在不止一种意见,如果标准试图强制执行“无原始循环”,那么可能永远不会包含基于范围的 for 循环。

【讨论】:

    猜你喜欢
    • 2013-12-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 2012-09-04
    相关资源
    最近更新 更多