我们能依靠容量缩减技巧吗

Can we rely on the reduce-capacity trick?

本文关键字:依靠 容量 我们      更新时间:2023-10-16

是否在任何地方都能保证下面的减少容量技巧将"工作"?

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[尽管不是绑定的]来代替,这就没有意义了)

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

§23.2.18说:

表达式a.swap(b),表示标准容器abarray以外的容器类型,应交换ab的值不调用任何移动、复制或交换操作容器元素…

这保证了必须交换vector的内部指针。
但是,我找不到任何保证新创建的vector的容量的方法。

§21.4.21说basic_string默认构造函数的post条件之一是capacity()返回一个未指定的值。
§21.4.23说basic_string复制构造函数的post条件之一是capacity()返回的值至少和size()一样大。
§21.4.6.82说string::swap在常量时间内运行,这(有效地)需要交换内部指针。

据我所知,一个符合string::max_size() { return 4;}的实现,从一个缓冲区交换到另一个缓冲区的所有内部将是常数时间。(vector不能这么做)

显然,对这一切持保留态度。我引用的是2011年2月28日的c++草案,我找不到vector的复制构造函数的规范。此外,没有找到支持的证据与找到反对的证据是不一样的。

在他的"Effective STL "的勘误表页面上,Scott Meyers写道:

当字符串实现使用引用计数时,使用交换技巧使用复制构造函数不会减少容量,因为复制构造函数没有分配任何内存;它只是调整了a引用计数。一个更可靠的执行收缩适应的方法是通过range构造函数创建临时字符串,例如:字符串(s.begin (), s.end ()) .swap(年代);这个版本的交换技巧是对向量也更安全,因为它消除了复制构造函数将复制另一个vector的剩余容量(其中

至于"保证",Meyers指出:

语言警察要求我告诉你没有保证此技术将真正消除过剩容量。实现者可以自由地为向量和字符串提供多余的容量他们想这么做,有时他们也想这么做。[生效STL,第17条]

从http://www.gotw.ca/gotw/054.htm:

一些实现可能会选择将容量稍微四舍五入到它们的下一个更大的内部"块大小",结果是容量实际上最终比大小稍大。

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

如果字符串实现使用小字符串优化,那么您不能将容量降低到某个阈值以上。如果字符串实现使用写时复制,则不会发生写操作,也不会进行真正的复制。

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