【问题标题】:Why does std::copy_n take a template parameter instead of std::size_t?为什么 std::copy_n 采用模板参数而不是 std::size_t?
【发布时间】:2015-12-30 15:39:23
【问题描述】:

这么简单的问题。

template<class InputIt, class Size, class OutputIt>
OutputIt copy_n(InputIt first, Size count, OutputIt result);

为什么std::copy_n 使用类型来表示要复制的元素数量,而不是简单的std::size_t?我就是想不出理由。

template<class InputIt, class OutputIt>
OutputIt copy_n(InputIt first, std::size_t count, OutputIt result);

【问题讨论】:

  • 假设如果开发者突然调用那个函数,参数计数是signed int并且它有负值,如果countstd::size_t,它会做积分提升,那么我们会收到未定义的行为。
  • 一个明显的情况是所需的大小可能大于size_t的最大值

标签: c++ c++11


【解决方案1】:

在这种情况下,推测最初的基本原理几乎是徒劳的,但通过这种设计,copy_n 可以用负数来调用,例如intptrdiff_t 类型,在这种情况下它根本不做任何事情,标准化委员会的成员肯定很清楚这一点,他们是非常能干的人。


另一个优点是,对于特殊的迭代器,例如输入和输出迭代器,大小可能大于任何可能的指针差异,因此可能大于size_t 可以表示的大小。例如。对于 32 位 Windows 中大于 4GB 的文件也是如此。 copy_n 的定义用明显的指针/迭代器算术表示,“对于每个非负整数 i &lt; n,执行 *(result + i) = *(first + i)”,这似乎确实将这种优势降级为非常特殊的情况,但符号容纳纯输入和输出迭代器,如

中所述 C++11 §25.1/12:

在算法的描述中,运算符 +- 用于一些迭代器类别 它们不必被定义。在这些情况下,a+n 的语义与

的语义相同
X tmp = a;
advance(tmp, n);
return tmp;

b-a的和return distance(a, b)的一样;


设计的通用性并没有固有的优势,它本身就是一个缺点,因为它更冗长,并且对不正确的使用代码生成的诊断不太容易理解。它的优点包括上面列出的两个。显然,委员会认为这些优势,或许还有其他优势 (?),超过了将 Size 作为模板参数的固有劣势。

【讨论】:

  • 他们可以指定除非使用无符号整数类型调用,否则行为将是未定义的。因为 std::copy_n 的整个想法是复制 n 个元素。不能是负数,不能是非整数,因为我们要处理许多元素。
  • @DeiDei:设计就是这样,表明委员会成员不同意你的观点。是的,这是一个权威论点。我发现只有这样的权威论据才能有效对抗故意无知的现实。
  • @DeiDei:对于容器大小使用有符号类型有一些合理的(尽管不是 IMHO 令人信服的)论点:虽然我不同意他在这个和其他主题上所说的很多,但 Lakos 在他的 Large如果您有兴趣,请扩展 C++ 书籍,但最好的方法是支持对 abs(c1.size() - c2.size()) 的天真/直观使用。此外,可以使用无类型宏之类的东西来提供大小,除非太大,否则默认为int。如果这些类型被随意传递给copy_n,那么具有未定义的行为是完全没有必要且非常危险的想法。
  • @DeiDei:我很好奇为什么让n 成为通用类型的模板参数可能是个问题?我想很少有 copy_n() 的类型被明确指定而不是被推断出来。 copy_n() 的当前规范有什么缺点?避免隐式有符号到无符号的转换有一个明显的好处。
【解决方案2】:

我猜这是因为通用性
C++ 中的容器size_type 通常是size_t。但是,如果您使用自定义容器或使用自定义分配器,则可能不是这种情况,因此需要使用模板参数。

对于custom containersize_type 不必是size_t 的类型定义(它必须是an unsigned integer large enough to represent all positive values of difference_type)。

对于 STL 容器,size_typeallocator::size_type 的类型定义,default allocatorsize_t。但是,如果您指定自定义分配器,则类型可能会有所不同。

【讨论】:

  • 可能是iterator_traits&lt;OutputIt&gt;::difference_type。并指定distance(result, return_value) == count。但是对于仅输入和仅输出的迭代器,它将具有模糊的含义。
  • @ConstantinBaranov:在 C++11 中,copy_n 被指定为“对于每个非负整数 i copy 也以这种方式指定,并且可以与此类迭代器一起使用。嗯。值得调查。
  • 哦,这是在 C++11 §25.1/12 中定义的。那么今天也学到了一些东西。还没死,哈利路亚!哦,该死,我是无神论者。好吧,无论如何。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-13
  • 2012-11-19
  • 1970-01-01
  • 2020-11-29
相关资源
最近更新 更多