2015-06-30 89 views
3

为什么这么多的电话复制缺点,我只希望只有最后九个?甚至根本不会返回价值优化。为什么这么多的复制,而转换/复制矢量

struct C 
{ 
    int _i; 
    C(int i) : _i(i) {} 
    C(const C& other) { cout << "copy cons from " << other._i << " to " << _i << endl; _i = other._i; } 
}; 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    vector<int> vi{ 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 
    vector<C> vc; 
    transform(vi.begin(), vi.end(), back_inserter(vc), 
     [](int i) 
    { 
     return C(i); 
    }); 
} 

输出:

copy cons from 1 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 5 to - 842150451 
copy cons from 6 to - 842150451 
copy cons from 1 to - 842150451 
copy cons from 2 to - 842150451 
copy cons from 3 to - 842150451 
copy cons from 4 to - 842150451 
copy cons from 5 to - 842150451 
copy cons from 6 to - 842150451 
copy cons from 7 to - 842150451 
copy cons from 8 to - 842150451 
copy cons from 9 to - 842150451 

回答

10

您的载体vc有增长几十倍。每次它都会分配一个更大的内存块,并复制原始元素。

您可以通过使用std::vector::reserve预留足够的空间来阻止它的发生。

vector<C> vc; 
vc.reserve(vi.size()); 
+1

谢谢,这是真的,但为什么它增长得如此缓慢,但没有例如。每次两倍?这不是很傻吗? – Yola

+3

@Yola它靠近两个因子增长。确切的因素取决于实施。 – juanchopanza

+0

许多实现使用接近黄金比例(〜1.62)的增长因子而不是2的主要原因是这可以防止内存碎片。请参阅[本答案](http://stackoverflow.com/a/1100426/358277)以获得更深入的解释 –

4

如从程序的输出观察时一个新元素被添加到该载体然后重新分配内存和已经载体的存在元素在新的地点被复制。

在运行避免内存重新分配的算法之前,您可以保留足够的内存。

vector<C> vc; 
vc.reserve(vi.size()); 

在这种情况下,可以避免复制构造函数的重复调用。

但它不是完整的故事。:)

C类具有转换构造

C(int i) : _i(i) {} 

它允许通过替换算法std::transform使用的呼叫简化创建矢量vc的元素算法std::copy的lambda表达式不使用lambda表达式。例如

std::copy(vi.begin(), vi.end(), std::back_inserter(vc)); 

但是,即使这不是完整的故事:)

当您使用std::transformstd::copy再就是使用两个构造函数:一个参数和拷贝construtor构造。

您可以避免使用复制建筑师并实现更高效的结果。简单地代替方法push_back最好使用方法emplace_back

如何使用这种方法?

最简单的一种是使用范围为基础的声明

for (int x : vi) vc.emplace_back(x); 

这是不够清晰可读。

如果你想使用一个标准的算法,你可以写

std::for_each(vi.begin(), vi.end(), [&vc](int x) { vc.emplace_back(x); }); 

在这两种情况下只有一个参数构造函数将被调用,避免调用拷贝构造函数。

自己检查一下。:)

+0

谢谢您的详细解答。 – Yola

+1

@Yola我希望这是一个有趣和有用的答案。:) –