STL vector中的emplace方法(23)

public member function
<vector>

std::vector::emplace

template <class... Args>
iterator emplace (const_iterator position, Args&&... args);
Construct and insert element
The container is extended by inserting a new element at position. This new element is constructed in place using args as the arguments for its construction.

通过在指定位置插入一个新的元素以扩展容器,新的元素的值为args或者是元素根据args的值构造。


This effectively increases the container size by one.

这是一种高效的增加容器大小的方法。


An automatic reallocation of the allocated storage space happens if -and only if- the new vector size surpasses the current vector capacity.

如果新的数组的大小超过了现在数组的capacity,那么将会自动发生重分配。


Because vectors use an array as their underlying storage, inserting elements in positions other than the vector end causes the container to shift all the elements that were after position by one to their new positions. This is generally an inefficient operation compared to the one performed by other kinds of sequence containers (such as list or forward_list). See emplace_back for a member function that extends the container directly at the end.

因为vector是使用array作为底层的存储容器,在指定位置插入元素代表着容器将要移动所有position后面的元素到一个新的位置。这通常都是很低效率的事情(相对于另一种更高效的插入序列容器,例如list或者forward_list),emplace_back则是一种直接在数组最后位置扩展的方法。


The element is constructed in-place by calling allocator_traits::construct with args forwarded.

元素是使用allocator_traits::construct以及args来构造。


A similar member function exists, insert, which either copies or moves existing objects into the container.

一个类似的方法是insert,这个则是通过拷贝或者移动存在的对象到容器内。



Parameters

position
Position in the container where the new element is inserted.

Member type const_iterator is a random access iterator type that points to a const element.

新元素插入容器的位置。

类型为随机访问迭代器。注意是const_iterator.

args
Arguments forwarded to construct the new element.

用于构造新元素的参数。


例子:

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main(int argc,char **argv)
{
	vector<int> vi={10,20,30};
	auto it=vi.begin();
	it++;
	cout<<"now vi is :";
	for_each(vi.begin(),vi.end(),[](int m){cout<<m<<" ";});
	vi.emplace(it,999);
	cout<<endl<<"after emplace(it,999)"<<endl;
	cout<<"now vi is :";
	for_each(vi.begin(),vi.end(),[](int m){cout<<m<<" ";});
	vi.emplace(vi.begin(),111);
	cout<<endl<<"after emplace(vi.begin(),111)"<<endl;
	cout<<"now vi is :";
	for_each(vi.begin(),vi.end(),[](int m){cout<<m<<" ";});
	
	auto it2=vi.emplace(vi.end(),222);
	cout<<endl<<"auto it2=vi.emplace(vi.end(),222)  ,it2="<<*it2<<endl;
	cout<<endl<<"after emplace(vi.end(),222)"<<endl;
	cout<<"now vi is :";
	for_each(vi.begin(),vi.end(),[](int m){cout<<m<<" ";});
	cout<<endl;	
		





}
运行截图:



Return value

An iterator that points to the newly emplaced element.

返回值是一个指向新插入的元素的iterator。


Member type iterator is a random access iterator type that points to an element.

类型为随机访问迭代器。


If a reallocation happens, the storage is allocated using the container's allocator, which may throw exceptions on failure (for the default allocatorbad_alloc is thrown if the allocation request does not succeed).

如果发生了重分配,将使用容器的分配器进行内存分配,这可能会抛出异常。(例如allocator这个默认的分配器在请求失败时会抛出bad_alloc异常)


Example

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// vector::emplace
#include <iostream>
#include <vector>

int main ()
{
  std::vector<int> myvector = {10,20,30};

  auto it = myvector.emplace ( myvector.begin()+1, 100 );
  myvector.emplace ( it, 200 );
  myvector.emplace ( myvector.end(), 300 );

  std::cout << "myvector contains:";
  for (auto& x: myvector)
    std::cout << ' ' << x;
  std::cout << '\n';

  return 0;
}

Output:
myvector contains: 10 200 100 20 30 300

Complexity

Linear on the number of elements after position (moving).
与插入位置后面元素的数目线性相关。(因为需要移动后面的元素)
If a reallocation happens, the reallocation is itself up to linear in the entire size.

如果发生重分配,重分配过程将导致与整个数组大小的线性时间的复杂度。(复制)


Iterator validity

If a reallocation happens, all iterators, pointers and references related to this container are invalidated.

如果发生重分配,所由的迭代器,指针以及引用都将失效。


Otherwise, only those pointing to position and beyond are invalidated, with all iterators, pointers and references to elements before position guaranteed to keep referring to the same elements they were referring to before the call.

否则,只有那些指向position以及更后面的将会失效,所有position之前的迭代器,指针,引用依旧有效。


Data races

The container is modified.

容器将被修改。

If a reallocation happens, all contained elements are modified.

如果发生重分配,容器内所有元素都将被修改。


Otherwise, none of the elements before position is accessed, and concurrently accessing or modifying them is safe.

否则,position之前的元素不会被访问,同时修改以及访问他们都是安全的。


Exception safety

If position is end, and no reallocations happen, there are no changes in the container in case of exception (strong guarantee).

如果位置为end,并且不发生重分配,发生异常的规则不变。


If a reallocation happens, the strong guarantee is also given if the type of the elements is either copyable or no-throw moveable.

如果发生重分配,并且元素的拷贝或者移动构造不会抛出异常,发生异常的规则也是一样的。


Otherwise, the container is guaranteed to end in a valid state (basic guarantee).

否则,容器保证最后依旧有效。


If allocator_traits::construct is not supported with the appropriate arguments, or if position is not valid, it causes undefined behavior.

如果allocator_traits::construct不支持该元素,或者position不是有效的,将导致未知的行为。


//翻译的不好的地方请多多指导,可以在下面留言或者点击左上方邮件地址给我发邮件,指出我的错误以及不足,以便我修改,更好的分享给大家,谢谢。

转载请注明出处:http://blog.youkuaiyun.com/qq844352155

2014-8-17

于GDUT





<think>好的,我现在需要回答用户关于C++中STL vector内存分配的问题。用户可能对vector的内部机制不太熟悉,特别是内存分配策略和如何高效使用。首先,我应该回忆vector的基本工作原理,包括动态数组的特性、自动扩容机制,以及相关的成员函数。 接下来,我需要考虑用户可能的背景。他们可能是刚开始学习C++,或者在使用vector时遇到了性能问题,比如频繁的重新分配导致效率低下。因此,回答需要详细但不过于复杂,涵盖关键点,如容量管理、扩容策略、reserve()和shrink_to_fit()的使用,以及注意事项。 我应该解释vector如何通过动态数组实现,当元素增加超过当前容量时,会分配更大的内存块,通常是将容量翻倍。这个扩容过程涉及到元素的移动和旧内存的释放,这可能导致性能开销。因此,强调使用reserve()预先分配足够空间的重要性,可以避免多次重新分配。 另外,用户可能对如何减少内存占用感兴趣,所以需要提到shrink_to_fit(),但也要说明它不一定保证减少容量,依赖于实现。同时,内存分配器的概念虽然重要,但可能对新手来说比较复杂,可以简要提及,避免深入细节。 还要注意代码示例的正确性和清晰性,比如展示reserve()的使用,以及容量和大小的区别。在注意事项部分,要强调避免在循环中频繁添加元素而不预留空间,以及正确使用swap技巧来释放内存。 最后,确保语言简洁,结构清晰,使用列表和代码块提高可读性。检查是否有遗漏的关键点,比如vector的内存分配策略可能因编译器实现而异,但通常是以指数级增长,如VS的1.5倍扩容。同时,指出如何通过size()和capacity()函数监控内存使用情况,帮助用户进行调试和优化。</think>以下是关于C++ STL `vector` 内存分配机制的详细说明(附关键代码示例): --- ### **核心分配机制** 1. **动态数组特性** - 底层实现为连续内存空间的动态数组 - 自动管理内存分配/释放 - 扩容时遵循特定策略重新分配内存 2. **容量增长策略** ```cpp vector<int> v; for(int i=0; i<5; ++i) { v.push_back(i); cout << "Size: " << v.size() << " Capacity: " << v.capacity() << endl; } ``` 典型输出: ``` Size:1 Capacity:1 Size:2 Capacity:2 Size:3 Capacity:4 // 翻倍扩容 Size:4 Capacity:4 Size:5 Capacity:8 // 再次翻倍 ``` 3. **标准扩容算法** - 常见实现采用 $新容量 = 旧容量 \times growth\_factor$ - GCC: 2倍扩容($growth\_factor=2$) - MSVC: 1.5倍扩容(更节省内存) --- ### **关键成员函数** | 函数 | 时间复杂度 | 作用描述 | |----------------------|------------|------------------------------| | `reserve(n)` | $O(n)$ | 预分配至少n个元素的内存空间 | | `shrink_to_fit()` | $O(n)$ | 请求释放未使用的容量空间 | | `capacity()` | $O(1)$ | 返回当前分配的总容量 | | `size()` | $O(1)$ | 返回当前元素数量 | --- ### **内存优化技巧** 1. **预分配策略** ```cpp vector<LargeObject> data; data.reserve(1000); // 避免多次重新分配 for(int i=0; i<1000; ++i) { data.emplace_back(createLargeObject()); } ``` 2. **内存释放技巧** ```cpp vector<int>().swap(v); // 清空并释放所有内存 v.shrink_to_fit(); // C++11起推荐方式 ``` 3. **移动语义优化** ```cpp vector<string> mergeVectors(vector<string>&& a, vector<string>&& b) { a.reserve(a.size() + b.size()); a.insert(a.end(), std::make_move_iterator(b.begin()), std::make_move_iterator(b.end())); return a; // 利用移动语义避免拷贝 } ``` --- ### **内存布局示意图** ``` +-------------+-----------------+ | vector对象 | 堆内存 | | (栈/堆) | [元素1][元素2]… | | - _M_start | | | - _M_finish | | | - _M_end_of_storage | +-------------+-----------------+ ``` --- ### **性能注意事项** 1. **插入操作成本** - `push_back` 均摊时间复杂度为 $O(1)$ - 最坏情况单次插入为 $O(n)$(触发扩容时) 2. **迭代器失效场景** ```cpp vector<int> v{1,2,3}; auto it = v.begin(); v.push_back(4); // 可能导致迭代器失效 // 危险操作:cout << *it << endl; ``` 3. **异常安全保证** - C++11起`push_back`提供强异常安全保证 - 元素类型需满足移动构造函数noexcept --- ### **高级用法:自定义分配器** ```cpp template<typename T> using CustomAllocVector = vector<T, MyAllocator<T>>; // 使用自定义内存池 CustomAllocVector<int> v; v.reserve(1024); // 使用MyAllocator分配内存 ``` --- 通过合理利用这些特性,可以在保证代码简洁性的同时,实现高效的内存管理。建议在性能关键代码中: 1. 优先使用`emplace_back`而非`push_back` 2. 对已知大小的容器提前`reserve` 3. 使用`data()`直接访问底层数组(C++11起)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值