最近我重读了ISO C ++标准,并发现了非常有趣的注意事项:
请注意,对于
std::vector
,T
类型std::vector<T>
的唯一约束是类型T
必须具有复制构造函数。实际上,如果在插入时向量的内存已满,则分配size = 2 * oldSize
的新内存(这取决于实现),然后在其中复制旧元素并插入该元素。
但等等?
要分配类型的新内存,我们需要这样的内容ptr = new T[2*size];
T
可能没有默认构造函数?std::vector
如何通过“仅复制构造函数”来做到这一点?使用了哪些实现和语言习语?答案 0 :(得分:27)
通过调用 allocator 函数 allocate()来获取原始内存并调用allocator construct (iterator,val) )使用 placement new 通过复制构建元素,即类似于:
/* approach similar to std::uninitialized fill taken */
template<typename T, typename A >
vector<T,A>::vector( size_type n, const T& val, const A& a) : alloc( a) // copy the allocator
{
/* keep track of which elements have been constructed
* and destroy those and only those in case of exception */
v = alloc.allocate( n); // get memory for elements
iterator p; // declared before try{} so it is still valid in catch{} block
try {
iterator end = v + n;
for( p = v; p != end; ++p)
alloc.construct( p, val); /* construct elements (placement new):
e g. void construct( pointer p, const T& val)
{ ::new((void *)p) T( val); } */
last = space = p;
} catch( ...) {
for( iterator q = v; q != p; ++q)
alloc.destroy( q); /* destroy constructed elements */
alloc.deallocate( v, n); /* free memory */
throw; /* re-throw to signal constructor that failed */
}
}
在C ++中,allocator用于隔离必须从物理内存细节分配内存的算法和容器的实现者。
也可以直接使用uninitialized_fill:
std::uninitialized_fill( v, v + n, val); /* copy elements with (placement new):
e g. void construct( pointer p,
const T& val)
{ ::new((void *)p) T( val); } */
Bjarne Stroustrup的“C ++ ...第3版”中详细介绍了这一点。 Here是基于此编写的示例。
答案 1 :(得分:4)
作为一般规则,标准容器分开分配
从初始化开始(就像你写的任何容器一样)。
标准容器使用非常复杂的机制
允许自定义分配和初始化,但是
在默认情况下,它归结为使用
operator new
/ operator delete
函数分配内存,
placement new用于初始化它,以及显式调用
析构函数来销毁对象。换句话说,insteaad
顺序:
p = new T[n];
// ...
delete [] p;
它使用:
p = operator new( n * sizeof( T ) );
for ( int i = 0; i != n; ++ i ) {
new ( p + i ) T( otherValue );
}
// ...
for ( int i = 0; i != n; ++ i ) {
p->~T();
}
operator delete( p );
(这是一个彻底的简化,以显示基本概念。 在实践中,出于例外的原因,它会更复杂 例如,安全。)
答案 2 :(得分:1)
考虑一下emplace_back():很可能vector会分配一块新的unititialized内存,然后运行placement new来就地复制构造对象。