我们可以依靠减少容量的技巧吗?

时间:2011-10-19 22:32:08

标签: c++ std

实际上是否可以保证以下减少容量技巧“起作用”?

int main() {
   std::string s = "lololololol";
   s = "";                        // capacity still non-zero

   string(s).swap(s);             // ?
}

它对我来说似乎没有“起作用”(因为容量保持非零),而且我在标准中找不到任何东西,而不是“内容”必须在两者之间交换。两个[这里,相同]的对象。

同样,对于序列容器:

int main() {
   vector<int> v { 1,2,3,4,5 };
   v.clear();                   // capacity still non-zero

   vector<int>(v).swap(v);      // ?
}

据我所知,这个“技巧”是半广泛使用的;也许这种广泛采用是错误的?

(当然,在C ++ 11中我们有shrink_to_fit [尽管是非约束性的],但这种做法没有实际意义。)

4 个答案:

答案 0 :(得分:6)

我一直被告知,没有保证降低容量的标准方法。所有方法都已经(现在仍然是)实现定义。

§23.2.1\ 8说:

  

表达式a.swap(b),用于标准的容器ab   除array以外的容器类型,应交换ab的值   不对个人调用任何移动,复制或交换操作   容器元素......

这保证了必须交换向量的内部指针 但是,我找不到任何可以保证新创建的载体容量的东西。

§21.4.2\ 1表示basic_string默认构造函数的一个帖子条件是capacity()返回未指定的值。
§21.4.2\ 3表示其中一个basic_string复制构造函数的帖子条件是capacity()返回的值至少与size()一样大。
§21.4.6.8\ 2表示string::swap在恒定时间内运行,这有效地要求交换内部指针。

据我所知,一致的实现可以有string::max_size() { return 4;},因此将所有内部交换从一个缓冲区交换到另一个缓冲区因此是恒定的时间。 (虽然矢量不能这样做)

显然,把这一切都拿出一粒盐。我引用了2011年2月28日的C ++草案,我找不到向量的复制构造函数的规范。此外,没有找到 的证据与查找 的证据不同。

答案 1 :(得分:4)

errata page的“有效STL”中,Scott Meyers指出:

  

当字符串实现使用引用计数时,交换技巧   使用复制构造函数不会降低容量,因为   复制构造函数没有分配任何内存;它只是调整一个   引用计数。执行缩小拟合的更可靠方法是   通过范围构造函数创建临时字符串,例如,   string(s.begin(),s.end())。swap(s);这个版本的交换技巧是   对于矢量也更安全,因为它消除了复制的任何机会   构造函数将复制其他向量的超额容量(其中   允许实现)。

关于'保证',迈耶斯指出:

  

语言警察要求我通知你没有   保证这项技术将真正消除过剩的产能。   如果,实施者可以自由地给出向量和字符串过剩的容量   他们想要,有时他们想要。 [有效的STL,第17项]

答案 2 :(得分:2)

来自http://www.gotw.ca/gotw/054.htm

  

某些实现可能会选择将容量略微舍入到   他们的下一个更大的内部“块大小”,结果是   容量实际上最终略大于大小。

答案 3 :(得分:0)

这是如何工作的可能完全是实现定义的。与vector之类的容器不同,字符串可以具有非常不同的实现。

如果字符串实现使用小字符串优化,那么您不能将容量降低到超过某个阈值。如果字符串实现使用copy-on-write,则不会发生写入,也不会进行实际复制。

根据http://www.gotw.ca/gotw/054.htm,缩小到适合和完全清楚是不同的技巧。如果打算完全清除,那么使用默认构造的字符串进行交换可以获得更好的结果。