我有一个将一个向量复制到另一个向量的函数(还有很多其他的东西)。下面是代码的简化版本。
void Fun(std::vector<double> &in, std::vector<double> &out) {
out = in;
}
字符串
我关心的是最大化效率,因为函数将运行多次。因此,我希望尽可能避免重新分配内存。向量“in”可能已经具有为其保留的大量存储器。所以,如果我做了一个手动实现,我相信我可以完成这一点。举例来说:
void Fun(std::vector<double> &in, std::vector<double> &out) {
out.resize(in.size());//note - if the capacity of out is greater than in.size(), this will involve no memory release or allocation
for (unsigned int i = 0;i<in.size();i++) {
out[i] = in[i];
}
}
型
如果in.size()小于out的现有容量,那么后面的实现将不会释放或分配任何新的堆内存。
问题是-我的原始实现会做同样的事情吗?也就是说,如果我简单地做了“out = in”,std::vector会自动以一种内存有效的方式来做这件事吗?“?
特别是,我担心的是,也许“出=进;“行可能会执行一些操作,例如释放当前分配给out的所有堆内存,然后重新分配它。与此等效的东西:
void Fun(std::vector<double> &in, std::vector<double> &out) {
out.clear();
out.shrink_to_fit();//releasing memory from heap
out.resize(in.size());//reallocating memory from heap
for (unsigned int i = 0;i<in.size();i++) {
out[i] = in[i];
}
}
型
2条答案
按热度按时间9fkzdhlc1#
std::vector::operator=
在C库中的实现是很久以前就存在的。几乎可以肯定的是,它的作者知道他们在做什么,结合现代C编译器,它将生成最佳代码,以最大限度地减少工作量和动态分配。operator=
的作者非常聪明。他们比我聪明。他们比你聪明。很有可能,所示的优化此操作的尝试最多会达到平衡。在最坏的情况下,当
out
小于in.size()
时,它最终会在resize()
中进行一系列毫无意义的零初始化,除非编译器足够聪明,可以优化它。如果有特定的知识,在一个特定的用例中,股票
out=in;
导致可测量的次优性能,那么某种微优化可能是谨慎的;但是,仅仅是“关心效率最大化”,就应该有具体的东西来评价。km0tfn4u2#
向量“in”可能已经具有为其保留的大量存储器。
[...]我的原始实现会做同样的事情吗?
我不知道有任何实现仅仅因为要复制的
vector
有很多.capacity()
就保留了多余的内存。此外,第二个代码片段不会保留超过存储in
中所有元素所需的内存,并且它首先默认构造额外的元素,然后为它们分配新值。对于double
s,这可能没什么关系,但对于非平凡类型,这可能会产生明显的差异。原始的out = in;
永远不会比第二个代码片段中的代码慢。如果你想保留
in
所保留的内存,你可以手动使用.reserve()
:字符串
关于你的问题的补充:
特别是,我担心
out = in;
行可能会做一些事情,比如释放当前分配给out的所有堆内存,然后重新分配它。与此等效的东西:型
不,这不太可能。从cppreferece开始:
[...]否则,
*this
拥有的内存可能会在可能的情况下重新使用。在任何情况下,最初属于*this
的元素都可以被销毁或被逐元素复制赋值替换。一个正常的实现会尽可能地重用已经分配的内存。该实现可能会对不同的类型使用不同的方法,以使副本分配尽可能有效。对于普通的可复制类型(如
double
),它可能是out.resize(in.size())
,然后是std::copy
。对于更复杂的类型,它可以out.reserve(in.size());
,复制赋值out
中的现有元素,然后复制构造其余的元素(如果是out.size() < in.size()
)-或者它可以out.clear(); out.reserve(in.size());
,然后复制构造所有元素。这取决于容器中的类型。如果
out
比in
有更多的容量,它将(几乎肯定)不会shrink_to_fit
(理论上可能会导致不必要的重新分配),而是保留多余的分配供以后使用,如this example所示,所有主要的实现即使在复制分配了一个小得多的vector
之后也会保留容量。