<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Soul Of Free Loop &#187; STL</title>
	<atom:link href="https://zohead.com/archives/tag/stl/feed" rel="self" type="application/rss+xml" />
	<link>https://zohead.com</link>
	<description>Uranus Zhou&#039;s Blog</description>
	<lastBuildDate>Sat, 19 Jul 2025 15:42:46 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.8</generator>
	<item>
		<title>STL中const_iterator、reverse_iterator转换为iterator</title>
		<link>https://zohead.com/archives/stl-const-reverse-iterator/</link>
		<comments>https://zohead.com/archives/stl-const-reverse-iterator/#comments</comments>
		<pubDate>Fri, 25 May 2012 15:25:39 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[const_iterator]]></category>
		<category><![CDATA[iterator]]></category>
		<category><![CDATA[reverse_iterator]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[Vector]]></category>
		<category><![CDATA[转换]]></category>
		<category><![CDATA[随机]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=191</guid>
		<description><![CDATA[本文同步自（如浏览不正常请点击跳转）：https://zohead.com/archives/stl-const-reverse-iterator/ STL中的容器类（Container）一般提供了4个迭代器：iterator、const_iterator、reverse_iterator、const_reverse_iterator，对于 container&#60;T&#62; 而言，其中 const_iterator 相当于 const T *，const_iterator 指向的元素不能做修改操作。 STL 容器的 begin() 和 end() 默认都提供了 iterator 和 con [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（如浏览不正常请点击跳转）：<a href="https://zohead.com/archives/stl-const-reverse-iterator/" target="_blank">https://zohead.com/archives/stl-const-reverse-iterator/</a></p>
<p>STL中的容器类（Container）一般提供了4个迭代器：iterator、const_iterator、reverse_iterator、const_reverse_iterator，对于 container&lt;T&gt; 而言，其中 const_iterator 相当于 const T *，const_iterator 指向的元素不能做修改操作。</p>
<p>STL 容器的 begin() 和 end() 默认都提供了 iterator 和 const_iterator 的迭代器，相应的 rbegin() 和 rend() 则也分别提供了 reverse_iterator 和 const_reverse_iterator 的迭代器用于从容器的尾端反向遍历。</p>
<p>最近写的代码中刚好要用到 const_iterator 迭代器，发现由于 STL 提供的一些容器操作函数像 insert、erase 的参数必须为 iterator，这时就不能用 const_iterator 做参数（不能直接转换），以下为个人经验结果。</p>
<p><strong><span style="color: #ff0000;">1、const_iterator 转换为 iterator：</span></strong></p>
<p>iterator 可以隐式转换为 const_iterator，但反过来就不行，就算祭出强制类型转换的杀招应该也会编译报错，这是可以用折中的办法解决：</p>
<p><em><span style="color: #008000;">vector&lt;sss&gt; v_test;</span></em><br />
<em><span style="color: #008000;">vector&lt;sss&gt;::iterator i_test;</span></em><br />
<em><span style="color: #008000;">vector&lt;sss&gt;::const_iterator c_test;</span></em><br />
<em><span style="color: #008000;">...</span></em><br />
<em><span style="color: #008000;">c_test = ....</span></em><br />
<em><span style="color: #008000;">...</span></em><br />
<em><span style="color: #008000;">i_test = v_test.begin();</span></em><br />
<em><span style="color: #008000;">advance(i_test, distance&lt;vector&lt;sss&gt;::const_iterator&gt;(i_test, c_test));</span></em></p>
<p>i_test 指向第一个元素，先通过 distance 得到 c_test 和 i_test 的偏移量，然后用 advance 将 i_test 往后移对应的偏移量即可。注意 distance 的模板类型必须为 const_iterator 类型，否则按照 STL 的默认类型推导，distance 中的 i_test 和 c_test 类型不同还是会出现编译报错。</p>
<p>当然如果你想偷懒简单点，也可以这样写，道理是一样的，这时类型推导就显得很好用了：</p>
<p><em><span style="color: #008000;">i_test = v_test.begin() + (c_test - v_test.begin());</span></em></p>
<p><strong><span style="color: #ff0000;">2、reverse_iterator 转换为 iterator：</span></strong></p>
<p>对于 reverse_iterator 可以调用 base() 得到 “与之对应” 的 iterator（与上面的环境一样）：</p>
<p><em><span style="color: #008000;">vector&lt;sss&gt; v_test;</span></em><br />
<em> <span style="color: #008000;"> vector&lt;sss&gt;::iterator i_test;</span></em><br />
<em> <span style="color: #008000;"> vector&lt;sss&gt;::reverse_iterator r_test;</span></em><br />
<em> <span style="color: #008000;"> ...</span></em><br />
<em> <span style="color: #008000;"> r_test = ....</span></em><br />
<em> <span style="color: #008000;"> ...</span></em><br />
<em> <span style="color: #008000;"> i_test = r_test.base();</span></em></p>
<p>但需要注意的是由于 STL 的 begin() 和 end()、rbegin() 和 rend() 是两个半闭合的区间，end() 并不是最后一个元素，rend() 也不是第一个元素，因此 end() 和 rbegin()、rend() 和 begin() 之间都是差了一个元素的。我们来看看 STL 标准上 base() 的说明：</p>
<p><em><span style="color: #008000;">The base iterator is an iterator of the same type as the one used to construct the reverse_iterator, but pointing to the element next to the one the reverse_iterator is currently pointing to (a reverse_iterator has always an offset of -1 with regards to its base iterator).</span></em></p>
<p>也就是 reverse_iterator 的 base() 返回的元素都是 reverse_iterator 所指向元素的下一个元素，这也是前面 “与之对应” 加引号的原因。因此在使用时要特别注意，例如如果要删除 reverse_iterator 指向的元素就需要这样（因为 erase 必须要 iterator 类型的参数）：</p>
<p><em><span style="color: #008000;">v_test.erase((++r_test).base());</span></em></p>
<p><strong><span style="color: #ff0000;">3、关于随机访问容器：</span></strong></p>
<p>STL 中随机访问容器是一个迭代器类型为随机访问迭代器的可逆容器，它提供常量缓冲时间来访问随机元素。而可逆容器是一个有双向迭代器的前向容器，它可以向后向后迭代通过容器。</p>
<p>常用到的顺序容器是将单一类型的元素聚集起来，然后根据位置来存储和访问这些元素。顺序容器的元素排列次序与元素值无关，而是由元素添加到容器里的次序决定。</p>
<p>平时经常用的 string、vector、deque 之类就是典型的随机访问容器，map、set、list 之类的就不是。</p>
<p>因此需要注意 STL 中的 sort 等函数的参数必须是随机访问迭代器，所以对 map、set、list 等容器是无效的。</p>
<p>以上为个人见解，有任何问题欢迎指正交流咯 ^_^。</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/stl-const-reverse-iterator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>bind2nd普通二元函数时无法使用引用类型参数的问题</title>
		<link>https://zohead.com/archives/cplusplus-bind2nd-reference/</link>
		<comments>https://zohead.com/archives/cplusplus-bind2nd-reference/#comments</comments>
		<pubDate>Wed, 09 May 2012 17:32:03 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[bind2nd]]></category>
		<category><![CDATA[find_if]]></category>
		<category><![CDATA[ptr_fun]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[引用]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=115</guid>
		<description><![CDATA[本文同步自（如浏览不正常请点击跳转）：https://zohead.com/archives/cplusplus-bind2nd-reference/ 在使用 STL 的 find_if、count_if 等函数时会发现这些函数使用的参数不是普通的函数指针，而是 functional 函数对象，实际使用函数对象时可以自己定义一个仿函数来实现（实现带参数的 operator () 即可），这个相对比较简单就不写出来了。但有些情况需要直接使用普通的二元函数指针，这时可以使用 ptr_fun 将函数指针转换为函数对象作为 find_if、count_if 等的参数。 先看一个能正常工作的二元函数不使 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自（如浏览不正常请点击跳转）：<a href="https://zohead.com/archives/cplusplus-bind2nd-reference/" target="_blank">https://zohead.com/archives/cplusplus-bind2nd-reference/</a></p>
<p>在使用 STL 的 find_if、count_if 等函数时会发现这些函数使用的参数不是普通的函数指针，而是 functional 函数对象，实际使用函数对象时可以自己定义一个仿函数来实现（实现带参数的 operator () 即可），这个相对比较简单就不写出来了。但有些情况需要直接使用普通的二元函数指针，这时可以使用 ptr_fun 将函数指针转换为函数对象作为 find_if、count_if 等的参数。</p>
<p>先看一个能正常工作的二元函数不使用引用类型参数的代码：</p>
<pre class="brush: cpp; highlight: [15,24,27,43]; title: cat &gt; test.cpp; notranslate">
#include &lt;iostream&gt;
#include &lt;vector&gt;
#include &lt;algorithm&gt;
#include &lt;functional&gt;

using namespace std;

class sss
{
public:
	explicit sss(int val) : value(val) {}

	sss(const sss&amp; org)
	{
		cout &lt;&lt; &quot;---copy &quot; &lt;&lt; &amp;org &lt;&lt; &quot; to &quot; &lt;&lt; this &lt;&lt; endl;
		value = org.value;
	}

	virtual ~sss() {}

	int value;
};

bool find_sss(sss s_chk, int val)
{
	bool ret = (s_chk.value == val);
	s_chk.value = 222;
	return ret;
}

int main(int argc, char ** argv)
{
	vector&lt;sss&gt; vvv;
	vector&lt;sss&gt;::iterator iii;

	vvv.push_back(sss(11));
	vvv.push_back(sss(12));
	vvv.push_back(sss(13));
	vvv.push_back(sss(14));
	vvv.push_back(sss(15));

	cout &lt;&lt; &quot;before find_if&quot; &lt;&lt; endl;
	iii = find_if(vvv.begin(), vvv.end(), bind2nd(ptr_fun(find_sss), 13));

	if (iii == vvv.end())
		cout &lt;&lt; &quot;not found&quot; &lt;&lt; endl;
	else
		cout &lt;&lt; &quot;index: &quot; &lt;&lt; (iii - vvv.begin()) &lt;&lt; &quot;, value: &quot; &lt;&lt; iii-&gt;value &lt;&lt; endl;

	return 0;
}
</pre>
<p>程序很简单，从 vector 中查找符合条件的 sss 对象，find_sss 就是要转换的二元函数指针，第一个参数是 sss 类，通过 ptr_fun 可以使本代码正常工作。</p>
<p>通过下面的运行输出能看出调用 find_sss 时进行了拷贝构造（本程序的编译环境为：Windows 7 32bit, Mingw gcc 3.4.5，Visual Studio 2010中稍有不同，主要在前面的拷贝次数上）：<br />
<strong><span style="color: #800000;"><br />
---copy 0x22ff10 to 0x552a58<br />
---copy 0x552a58 to 0x552ad8<br />
---copy 0x22ff10 to 0x552ae0<br />
---copy 0x552ad8 to 0x552af0<br />
---copy 0x552ae0 to 0x552af8<br />
---copy 0x22ff10 to 0x552b00<br />
---copy 0x22ff10 to 0x552b08<br />
---copy 0x552af0 to 0x552b18<br />
---copy 0x552af8 to 0x552b20<br />
---copy 0x552b00 to 0x552b28<br />
---copy 0x552b08 to 0x552b30<br />
---copy 0x22ff10 to 0x552b38<br />
before find_if<br />
---copy 0x552b18 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
---copy 0x552b20 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
---copy 0x552b28 to 0x22fdd0<br />
---copy 0x22fdd0 to 0x22fd40<br />
index: 2, value: 13<br />
</span></strong></p>
<p>接下来就是实际碰到的问题了，如果将 find_sss 的第一个参数改为 sss 的引用，即第 24 行改为：</p>
<p><span style="color: #006400;"><em><strong><span style="color: #008000;">bool find_sss(sss&amp; s_chk, int val)</span><br />
</strong></em></span></p>
<p>上面的代码就会编译出错（以 Visual Studio 2010 的错误输出为例）：</p>
<hr size="1" />
<p><span style="color: #0000ff;">C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xfunctional(341) : error C2535: “bool std::binder2nd&lt;_Fn2&gt;::operator ()(sss &amp;) const”: 已经定义或声明成员函数<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
C:\Program Files\Microsoft Visual Studio 10.0\VC\INCLUDE\xfunctional(335) : 参见“std::binder2nd&lt;_Fn2&gt;::operator ()”的声明<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
test.cpp(43): 参见对正在编译的类 模板 实例化“std::binder2nd&lt;_Fn2&gt;”的引用<br />
with<br />
[<br />
_Fn2=std::pointer_to_binary_function&lt;sss &amp;,int,bool,bool (__cdecl *)(sss &amp;,int)&gt;<br />
]<br />
</span></p>
<hr size="1" />
<p>网上的码农和攻城师们基本都认为是 STL 本身的问题，传递引用类型参数会造成 reference to reference 问题。</p>
<p>几番尝试之后，发现的解决方法如下：</p>
<p><strong>1、Visual Studio 2010下的不完美解决方法：</strong></p>
<p>将第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), bind2nd(pointer_to_binary_function&lt;sss, int, bool, bool(*)(sss&amp;, int)&gt;(find_sss), 13));<br />
</span></strong></p>
<p>这样通过自己给 pointer_to_binary_function 设置模板参数避免编译出错，实际运行中会发现 find_if 查找可以正常工作了，但第 27 行中修改引用类的值会没有效果，因为这种方式不是真正的引用，仍然有拷贝构造，由于需要用到这些二元函数的场合一般不需要修改数据，使用起来没有太大问题。</p>
<p><strong>2、gcc下的不完美解决方法：</strong></p>
<p>如果 gcc 下用上面的改动，你会发现由于 gcc 下 pointer_to_binary_function 只有 3 个参数，无法顺利修改编译，但可以这样折中，将第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), bind2nd(ptr_fun((bool(*)(sss, int)) find_sss), 13));<br />
</span></strong></p>
<p>通过强制类型转换来实现，稍显恶心，查找可以正常工作，但依然是拷贝构造。需要注意此方法如果在 Visual Studio 中使用会出错。</p>
<p><strong>3、终极解决方案- 使用 boost 库：</strong></p>
<p>首先头文件中增加：</p>
<p><strong><span style="color: #006400;">#include &lt;boost/functional.hpp&gt;</span></strong></p>
<p>然后原来的第 43 行改为：</p>
<p><strong><span style="color: #006400;">    iii = find_if(vvv.begin(), vvv.end(), boost::bind2nd(boost::ptr_fun(find_sss), 13));<br />
</span></strong></p>
<p>编译运行之后发现 find_if 查找可以正常工作，而且现在是真正的引用，只能说 boost 的 functional 相比 STL 的实在是好强大，哈哈。</p>
<p>运行输出如下（使用 Mingw gcc 3.4.5 编译），find_if 找到的值已经被 find_sss 修改：</p>
<p><strong><span style="color: #800000;">---copy 0x22ff10 to 0x7f2a58<br />
---copy 0x7f2a58 to 0x7f2ad8<br />
---copy 0x22ff10 to 0x7f2ae0<br />
---copy 0x7f2ad8 to 0x7f2af0<br />
---copy 0x7f2ae0 to 0x7f2af8<br />
---copy 0x22ff10 to 0x7f2b00<br />
---copy 0x22ff10 to 0x7f2b08<br />
---copy 0x7f2af0 to 0x7f2b18<br />
---copy 0x7f2af8 to 0x7f2b20<br />
---copy 0x7f2b00 to 0x7f2b28<br />
---copy 0x7f2b08 to 0x7f2b30<br />
---copy 0x22ff10 to 0x7f2b38<br />
before find_if<br />
<span style="color: #f00;">index: 2, value: 222</span><br />
</span></strong></p>
<p>以上仅为个人小心得，有任何问题欢迎指正，玩的开心咯 ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/cplusplus-bind2nd-reference/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>vector的push_back拷贝构造和空间占用分析</title>
		<link>https://zohead.com/archives/vector-push-back-space-copy/</link>
		<comments>https://zohead.com/archives/vector-push-back-space-copy/#comments</comments>
		<pubDate>Fri, 04 May 2012 18:30:56 +0000</pubDate>
		<dc:creator><![CDATA[Uranus Zhou]]></dc:creator>
				<category><![CDATA[C++]]></category>
		<category><![CDATA[技术]]></category>
		<category><![CDATA[push_back]]></category>
		<category><![CDATA[STL]]></category>
		<category><![CDATA[拷贝]]></category>
		<category><![CDATA[构造]]></category>
		<category><![CDATA[析构]]></category>
		<category><![CDATA[编程]]></category>

		<guid isPermaLink="false">http://zohead.com/?p=104</guid>
		<description><![CDATA[本文同步自：https://zohead.com/archives/vector-push-back-space-copy/ 这两天在实际程序中使用 STL 的 vector push_back 类对象时出现问题，偶尔发现 vector 在 push_back 时的调用类对象的拷贝构造函数和析构函数有点特别，简单做下分析。 程序代码： 功能很简单，main 中定义一个 sss 类对象和对应的 vector，然后在循环中改类成员的值，并依次 push_back 到 vector 中，类的构造函数、析构函数、拷贝构造函数中都加了对应的打印输出。循环运行了5次，往 vector 中增加了5个类成员。 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>本文同步自：<a href="https://zohead.com/archives/vector-push-back-space-copy/" target="_blank">https://zohead.com/archives/vector-push-back-space-copy/</a></p>
<p>这两天在实际程序中使用 STL 的 vector push_back 类对象时出现问题，偶尔发现 vector 在 push_back 时的调用类对象的拷贝构造函数和析构函数有点特别，简单做下分析。</p>
<p><span style="color: #f00;"><strong>程序代码：</strong></span></p>
<p><pre class="brush: cpp; highlight: [11,16,22,36]; title: cat &gt; test.cpp; notranslate">
#include &lt;iostream&gt;
#include &lt;vector&gt;

using namespace std;

struct sss
{
public:
	explicit sss(int val) : value(val)
	{
		cout &lt;&lt; &quot;---init sss &quot; &lt;&lt; this &lt;&lt; &quot;, value:&quot; &lt;&lt; value &lt;&lt; endl;
	}

	sss(const sss&amp; org)
	{
		cout &lt;&lt; &quot;---copy &quot; &lt;&lt; &amp;org &lt;&lt; &quot; to &quot; &lt;&lt; this &lt;&lt; endl;
		value = org.value;
	}

	~sss()
	{
		cout &lt;&lt; &quot;---destory sss &quot; &lt;&lt; this &lt;&lt; &quot;, value:&quot; &lt;&lt; value &lt;&lt; endl;
	}
 
	int value;
};

int main(int argc, char ** argv)
{
	sss s_tmp(11);
	int i = 0;
	vector&lt;sss&gt; vvv;

	for (i = 0; i &lt; 5; i++) {
		s_tmp.value++;
		vvv.push_back(s_tmp);
		cout &lt;&lt; &quot;size: &quot; &lt;&lt; vvv.size() &lt;&lt; &quot;, capacity: &quot; &lt;&lt; vvv.capacity() &lt;&lt; endl;
	}

	return 0;
}
</pre>
</p>
<p>功能很简单，main 中定义一个 sss 类对象和对应的 vector，然后在循环中改类成员的值，并依次 push_back 到 vector 中，类的构造函数、析构函数、拷贝构造函数中都加了对应的打印输出。循环运行了5次，往 vector 中增加了5个类成员。</p>
<p>实际运行输出如下：</p>
<hr size="1" />
<p>---init sss 0x22ff20, value:11<br /> ---copy 0x22ff20 to 0x5d2a58<br /> size: 1, capacity: 1<br /> ---copy 0x5d2a58 to 0x5d2ad8<br /> ---copy 0x22ff20 to 0x5d2adc<br /> ---destory sss 0x5d2a58, value:12<br /> size: 2, capacity: 2<br /> ---copy 0x5d2ad8 to 0x5d2ae8<br /> ---copy 0x5d2adc to 0x5d2aec<br /> ---copy 0x22ff20 to 0x5d2af0<br /> ---destory sss 0x5d2ad8, value:12<br /> ---destory sss 0x5d2adc, value:13<br /> size: 3, capacity: 4<br /> ---copy 0x22ff20 to 0x5d2af4<br /> size: 4, capacity: 4<br /> ---copy 0x5d2ae8 to 0x5d2b00<br /> ---copy 0x5d2aec to 0x5d2b04<br /> ---copy 0x5d2af0 to 0x5d2b08<br /> ---copy 0x5d2af4 to 0x5d2b0c<br /> ---copy 0x22ff20 to 0x5d2b10<br /> ---destory sss 0x5d2ae8, value:12<br /> ---destory sss 0x5d2aec, value:13<br /> ---destory sss 0x5d2af0, value:14<br /> ---destory sss 0x5d2af4, value:15<br /> size: 5, capacity: 8<br /> ---destory sss 0x5d2b00, value:12<br /> ---destory sss 0x5d2b04, value:13<br /> ---destory sss 0x5d2b08, value:14<br /> ---destory sss 0x5d2b0c, value:15<br /> ---destory sss 0x5d2b10, value:16<br /> ---destory sss 0x22ff20, value:16</p>
<hr size="1" />
<p><span style="color: #f00;"><strong>结果分析：<br /> </strong></span></p>
<p>vector 每次调用 push_back 时都会拷贝一个新的参数指定的 sss 类对象，这会调用 sss 的拷贝构造函数，第一次的 copy 正常，而且 vector 的实际容量也由 0  变为 1。</p>
<p>第二次调用 push_back，通过输出会发现调用了两次拷贝构造函数，一次析构函数，原来 vector 此时判断容量不够，将容量扩大为原来的两倍，变为 2，并将原来的元素再次拷贝一份存放到新的内存空间，然后拷贝新加的类对象，最后再释放原来的元素。</p>
<p>第三次调用 push_back 时，vector 自动扩大为4，因此拷贝构造函数调用了3次，析构函数调用了2次，程序最终退出了时就析构了 5 次加本身的 sss 类对象一共 6 次。</p>
<p><span style="color: #f00;"><strong>参考：</strong></span></p>
<p>由此看来，vector 的 push_back 在发现空间不足时自动将空间以 2 的指数增长：0 -&gt; 1 -&gt; 2 -&gt; 4 -&gt; 8 -&gt; 16 -&gt; 32 ...</p>
<p>查找资料后得知，如此设计的主要目的是为了尽可能的减小时间复杂度；如果每次都按实际的大小来增加 vector 的空间，会造成时间复杂度很高，降低 push_back 的速度。</p>
<p>另外关于 push_back 为什么会执行拷贝构造函数，push_back 的原型为：</p>
<p><em><span style="color: #008000;">void push_back(const _Ty&amp; _Val)</span></em></p>
<p>参数是以引用方式传递，按说不会拷贝，但 push_back 实际实现中判断空间不足时是调用 insert 函数添加元素：</p>
<p><em><span style="color: #008000;">void push_back(const _Ty&amp; _Val)</span></em><br /> <em><span style="color: #008000;">{</span></em><br /> <em><span style="color: #008000;">   // insert element at end</span></em><br /> <em><span style="color: #008000;">   if (size() &lt; capacity())</span></em><br /> <em><span style="color: #008000;">   #if _HAS_ITERATOR_DEBUGGING</span></em><br /> <em><span style="color: #008000;">   {</span></em><br /> <em><span style="color: #008000;">      // room at end, construct it there</span></em><br /> <em><span style="color: #008000;">      _Orphan_range(_Mylast, _Mylast);</span></em><br /> <em><span style="color: #008000;">      _Mylast = _Ufill(_Mylast, 1, _Val);</span></em><br /> <em><span style="color: #008000;">   }</span></em><br /> <em><span style="color: #008000;">   #else /* _HAS_ITERATOR_DEBUGGING */</span></em><br /> <em><span style="color: #008000;">      _Mylast = _Ufill(_Mylast, 1, _Val);</span></em><br /> <em><span style="color: #008000;">   #endif /* _HAS_ITERATOR_DEBUGGING */</span></em><br /> <em><span style="color: #008000;">   else</span></em><br /> <em><span style="color: #008000;">      insert(end(), _Val);</span></em><br /> <em><span style="color: #008000;">}</span></em></p>
<p><span style="color: #f00;"><strong>更新：</strong></span></p>
<p>2012-05-10：</p>
<p>近期在 Visual Studio 2010 中发现 vector 的实际空间增加顺序为：1 - 2 - 3 - 4 - 6 - 9 - 13 - 19 - 28 - 42 - 63 - 94 - 141 - 211 ...，有空时再继续研究。</p>
<p>以上只是个人粗略分析，有任何问题欢迎指正，玩的开心咯 ^_^</p>
]]></content:encoded>
			<wfw:commentRss>https://zohead.com/archives/vector-push-back-space-copy/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
