在啥情况下你应该更喜欢使用 std::copy 写入 cout?

Posted

技术标签:

【中文标题】在啥情况下你应该更喜欢使用 std::copy 写入 cout?【英文标题】: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 循环。 【参考方案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 循环。

【讨论】:

以上是关于在啥情况下你应该更喜欢使用 std::copy 写入 cout?的主要内容,如果未能解决你的问题,请参考以下文章

在啥情况下我应该在 C++ 中使用 memcpy 而不是标准运算符?

在使用 boost 共享互斥锁时,我应该在啥情况下使用 owns_lock() 函数

在啥情况下我们需要在数据库中使用组合键

在啥情况下 do-while 可以比 while 更有效率?

在啥情况下 REST API 应该返回 HTTP 状态 503

list和map在啥情况下使用?哪个效率更高一些?