在C++11中引入了shrink_to_fit
来补充特定的STL容器(如std::vector
、std::deque
、std::string
)。
摘要,它的主要功能是请求与相关联的容器,以减少其适应其大小的容量。但是,这个请求是非绑定的,容器实现可以自由地进行优化,并使向量的容量大于其大小。
此外,在前面的一个这样的问题中,OP被禁止使用shrink_to_fit
来将他的std::vector
的容量减少到它的大小。不这样做的理由如下:
shrink_to_fit
什么也不做,或者它会给您提供缓存位置问题,执行它是O(n) (因为您必须将每一项复制到它们的新的、较小的家园)。通常来说,留下记忆中的空白会更便宜。https://stackoverflow.com/users/80754/massa
有人能回答以下问题吗?
std::vector
是这样)。shrink_to_fit
存在的原因到底是什么呢?发布于 2014-05-06 12:07:10
引文中的论点成立吗?
量一量,你就会知道。你的记忆受到限制了吗?你能事先算出正确的尺寸吗?它对reserve
的效率将比事实发生后的收缩更有效。一般来说,我倾向于同意的前提是,大多数的使用可能是好的松懈。
如果是,那么将STL容器的容量缩小到其大小的正确方法是什么(至少对于std::vector)。
这个注释不仅适用于shrink_to_fit
,也适用于任何其他缩小方式。考虑到您不能将realloc
放在适当的位置,它涉及到获取不同的内存块并在那里进行复制,而不管您使用何种机制进行收缩。
如果有更好的方法收缩容器,那么shrink_to_fit存在的原因到底是什么呢?
请求是不具约束力的,但是替代方案没有更好的保证。问题是收缩是否有意义:如果有,那么提供一个shrink_to_fit
操作是有意义的,它可以利用对象被移动到一个新位置的事实。也就是说,如果类型T
有一个noexcept(true)
移动构造函数,它将分配新内存并移动元素。
虽然您可以在外部实现相同的操作,但是这个接口简化了操作。与shrink_to_fit
在C++03中的相同之处是:
std::vector<T>(current).swap(current);
但是,这种方法的问题是,当对临时副本进行复制时,它不知道current
将被替换,没有任何东西可以告诉库它可以移动所保存的对象。注意,使用std::move(current)
并不能达到预期的效果,因为它会移动整个缓冲区,维护相同的capacity()
。
在外部实现这一点要麻烦得多:
{
std::vector<T> copy;
if (noexcept(T(std::move(declval<T>())))) {
copy.assign(std::make_move_iterator(current.begin()),
std::make_move_iterator(current.end()));
} else {
copy.assign(current.begin(), current.end());
}
copy.swap(current);
}
假设我的条件是正确的..。这可能不是每次你想要这个操作时都要写的东西。
发布于 2014-05-07 01:26:51
由于这些论点本来是我的,所以我可以一个接一个地为它们辩护:
shrink_to_fit
什么也不做(.)
如前所述,标准规定(很多次,但就vector
而言,它是23.3.7.3节.)该请求是非绑定的,以允许优化的实现空间。这意味着实现可以将shrink_to_fit
定义为无操作。shrink_to_fit
不是作为非op实现的,那么您必须分配一个新的底层容器,其中包含容量size()
,复制(或者,在最好的情况下,移动)从旧的项目构造所有的N = size()
新项目,销毁所有旧的项目(在移动的情况下,这应该进行优化,但这可能会再次涉及旧容器上的循环),然后再对旧容器本身进行销毁。这是在libstdc++-4.9
中完成的,就像大卫罗德里格斯描述的那样,
_Tp(__make_move_if_noexcept_iterator(__c.begin()),__make_move_if_noexcept_iterator(__c.end()),__c.get_allocator().swap(__c);
在libc++-3.5
中,由__alloc_traits
中的一个函数执行大致相同的操作。
哦,一个实现绝对不能依赖于realloc
(即使它在::operator new
中使用malloc
进行内存分配),因为如果realloc
不能缩小内存(没有操作),或者按位复制(并且错过了适当的C++复制/移动构造函数所提供的重新调整指针的机会)。
当然,我们可以编写一个收缩内存分配器,并在其向量的构造函数中使用它。
在向量大于缓存线的简单情况下,所有这些移动都会给缓存带来压力。n = size()
,我认为这是建立在上面的,至少,您必须执行一个n
大小的分配、n
复制或移动构造、n
破坏和一个old_capacity
大小的去分配。正确的方法仍然是shrink_to_fit
..。你只需要要么不依赖它,要么非常清楚你的实现!
没有更好的方法,但是shrink_to_fit
存在的原因是,有时候你的程序可能会感觉到记忆压力,这是治疗它的一种方法。不是很好的方法,但还是。
哈哈!
发布于 2016-09-12 13:42:53
“交换技巧”将将向量调整到所需的精确大小(来自更有效的STL):
vector<Person>(persons).swap(persons);
当向量为空时,释放所有内存尤其有用:
vector<Person>().swap(persons);
由于保留未使用空间的分配,向量不断地绊倒了我的单元测试人员的内存泄漏检测代码,这就完美地解决了它们。
这是一个我并不关心运行时效率(大小或速度)的例子,但我确实关心内存的精确使用。
我真的不知道提供一个合法的功能的意义是什么。当我看到它被介绍时,我欢呼起来,当我发现它不能被信赖时,我就绝望了。
也许我们会在下一个版本中看到maybe_sort()。
https://stackoverflow.com/questions/23502291
复制