为啥 std::basic_string::substr 不遵循 [begin, end) 约定?

Posted

技术标签:

【中文标题】为啥 std::basic_string::substr 不遵循 [begin, end) 约定?【英文标题】:Why doesn't std::basic_string::substr follow the [begin, end) convention?为什么 std::basic_string::substr 不遵循 [begin, end) 约定? 【发布时间】:2016-09-28 05:50:50 【问题描述】:

方法std::basic_string::substr 有参数pos, count,指定位置元素的逻辑范围[pos, pos + count + 1)。相反,大多数标准库函数(例如,std::for_each)都有参数,其形式类似于begin, end,指定范围[begin, end)

这似乎是一个例外,因此,有些人会感到困惑(请参阅问题here、here、here 和here)。为什么这里没有使用通常的范围约定?另请注意,std::vector::erase,另一个随机访问容器的方法,确实遵循通常的约定。

【问题讨论】:

您可以通过使用 contrustor 获得相同的行为。例如。 std::string substringtext.begin(), text.end()。不知道为什么substr没有这么重载。 @Zereges:因为它是多余的。如果您有两个表示子字符串的迭代器,如果您也可以将它们传递给 std::string::string(),为什么还要将它们传递给 std::string::substr() 重载。 @MSalters STL 中有很多冗余的重载甚至函数。 STL 的设计初衷不是简约。 【参考方案1】:

历史原因。标准库有多个来源,其中之一是 STL。它带来了begin,end 约定。 std::string 早于 STL 并入标准库之前,有很多现有代码使用 .substr(pos,length)

【讨论】:

...我想如果我们现在设计这个库,std::string 看起来会很不一样。【参考方案2】:

一个简单的猜测:

您引用的不同方法具有不同的行为,这可能就是为什么有些使用迭代器而有些不使用的原因。

std::for_each 是通用的 - 拥有适用于任何容器(甚至原始数组)的通用版本的方法的最简单方法是使用迭代器。

std::vector::erase 是SequenceContainer 概念的一部分,因此它必须有一个可以在任何类型的容器上工作的“通用”表单(您可以使用poscount 来表示std::vector,但是std::liststd::set 呢?)。拥有这样的概念对于创建通用代码很有用:

template <typename C>
void real_remove(C &c, const typename C::value_type &value) 
     c.erase(std::remove(c.begin(), c.end(), value), c.end());

这只是因为std::...::erase 对任何 SequenceContainer 都有很好的定义。

另一方面,std::basic_string::substr 只是std::basic_string 的一部分(与erase 不同,它是std::vectorstd::list 的一部分...)并返回std::basic_string1(不是迭代器,你会在这里用迭代器做什么?)。

std::basic_string 中还有其他“非泛型”(即某些概念不强制)方法,通常是整个 find 方法家族,insert 具有 size_type、@987654341 的重载@,等等。

从主观角度来看,我认为最好有一个与其他容器不同的 std::basic_string,因为它不是(我不确定标准是否要求 std::basic_stringSequenceContainer 或任何东西一样)。

1 你不能在这里返回迭代器,因为你想要一个新的std::basic_string,所以你会有一个采用迭代器但返回一个对象的方法......我会觉得这更令人不安而不是pos/count 而不是first/last

【讨论】:

【参考方案3】:

我不知道为什么,我不在那里,但是您错过了 [begin, end) 约定的范围构造函数。

template< class InputIt >
basic_string( InputIt first, InputIt last,
              const Allocator& alloc = Allocator() );

【讨论】:

以上是关于为啥 std::basic_string::substr 不遵循 [begin, end) 约定?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 DataGridView 上的 DoubleBuffered 属性默认为 false,为啥它受到保护?

为啥需要softmax函数?为啥不简单归一化?

为啥 g++ 需要 libstdc++.a?为啥不是默认值?

为啥或为啥不在 C++ 中使用 memset? [关闭]

为啥临时变量需要更改数组元素以及为啥需要在最后取消设置?

为啥 CAP 定理中的 RDBMS 分区不能容忍,为啥它可用?