STL中std::vector的reserve()实现 考虑从“C++编程语言,第四版”,Bjarne Stroustrup:中的STD::vector::SaveFuffE()的实现。 template<class T, class A> void vector<T,A>::reserve(size_type newalloc) { if (newalloc<=capacity()) return; vector_base<T,A> b {vb.alloc,newalloc}; // get new storage // (see PS of question for details on vb data member) T* src = elem; // ptr to the start of old storage T* dest = b.elem; // ptr to the start of new storage T* end = elem+size(); // past-the-end ptr to old storage for (; src!=end; ++src, ++dest) { new(static_cast<void*>(dest)) T{move(*src)}; // move construct src–>~T(); // destroy } swap(vb,b); // install new base (see PS if needed) } // implicitly release old space(when b goes out of scope)
这可能会失败:STL中std::vector的reserve()实现 考虑从“C++编程语言,第四版”,Bjarne Stroustrup:中的STD::vector::SaveFuffE()的实现。 template<class T, class A> void vector<T,A>::reserve(size_type newalloc) { if (newalloc<=capacity()) return; vector_base<T,A> b {vb.alloc,newalloc}; // get new storage // (see PS of question for details on vb data member) T* src = elem; // ptr to the start of old storage T* dest = b.elem; // ptr to the start of new storage T* end = elem+size(); // past-the-end ptr to old storage for (; src!=end; ++src, ++dest) { new(static_cast<void*>(dest)) T{move(*src)}; // move construct src–>~T(); // destroy } swap(vb,b); // install new base (see PS if needed) } // implicitly release old space(when b goes out of scope),c++,c++11,vector,stl,C++,C++11,Vector,Stl,这可能会失败: memcpy() 对于所有其他类型的对象,它都会失败,因为它不尊重它复制的对象的语义(复制构造) 问题的例子: 如果对象的构造函数将一些内部指针设置为内部成员,则memcpy()将复制原始指针的值,该值将不会正确更新,并继续指向将释放的内存区域 如果对象包含共享\u ptr,则对象计数将变得不一致(memcpy()将复制指针而不增加其引用计数,然后swap()将确保原始共享指针位于b中,b将被释放,因此共享指针引用计数将递减) 正如T.C在评论中指出的,一旦向量存储了非P
memcpy()
- 对于所有其他类型的对象,它都会失败,因为它不尊重它复制的对象的语义(复制构造)
- 如果对象的构造函数将一些内部指针设置为内部成员,则
将复制原始指针的值,该值将不会正确更新,并继续指向将释放的内存区域memcpy()
- 如果对象包含
,则对象计数将变得不一致(共享\u ptr
将复制指针而不增加其引用计数,然后memcpy()
将确保原始共享指针位于b中,b将被释放,因此共享指针引用计数将递减)swap()
正如T.C在评论中指出的,一旦向量存储了非POD数据,
memcpy()
就会导致UB(未定义的行为).若元素保留一个指向自己的指针,或者依赖于自己的地址,这将失败。若元素复制了这个指针,或者将这个指针复制到lambda或类似的东西,这就足够了。@AaronI这个建议是UB,简单明了,所以知道得更好的Bjarne和co为什么不使用它。尽管如此…任何可以使用指向自身的指针的元素都是一个对象,因此它不需要存储自己的地址,因为它总是可以在方法中使用this
来访问它。而且因为this
指针在概念上并不存在-它是在调用方法的任何对象时生成的-它不能成为wrong.这只是UB,句号,用于非平凡的可复制类型。目的地没有活体。@T.C.当然是UB!但是我认为值得尝试向memcpy
瘾君子解释,并且用memcpy
参数解释一个对象超过了它的记忆总和;-)当然,但值得强调的是它在一般情况下,UB的实现可以让您的cat怀孕,即使问题的类是struct A{~A(){};
.UB==Undefined Behavior.POD太强了,顺便说一句。您只需要少量的可复制性。
template<class T, class A>
void vector<T,A>::reserve(size_type newalloc)
{
if (newalloc<=capacity()) return;
vector_base<T,A> b {vb.alloc,newalloc}; // get new space
memcpy(b.elem, elem, sz); // copy raw memory
// (no calls to ctors or dtors)
swap(vb,b); // install new base
} // implicitly release old space(when b goes out of scope)
// used as a data member in std::vector
template<class T, class A = allocator<T> >
struct vector_base { // memory structure for vector
A alloc; // allocator
T* elem; // start of allocation
T* space; // end of element sequence, start of space allocated for possible expansion
T* last; // end of allocated space
vector_base(const A& a, typename A::size_type n)
: alloc{a}, elem{alloc.allocate(n)}, space{elem+n}, last{elem+n} { }
~vector_base() { alloc.deallocate(elem,last–elem); } // releases storage only, no calls
// to dtors: vector's responsibility
//...
};
// std::vector
template<class T, class A = allocator<T> >
class vector {
vector_base<T,A> vb; // the data is here
void destroy_elements();
public:
//...
};