考虑“The C++ Programming Language, 4th ed., Bjarne Stroustrup”一书中 std::vector::reserve() 的实现:
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)
请注意,在循环中,对于 vector 中的每个元素,至少对 ctor 和 dtor 进行一次调用(如果元素的类具有基类,或者类或其基类具有数据成员,则可能触发更多此类调用与 Actor )。 (在书中,for-loop实际上是一个单独的函数,但为了简单起见,我在这里将它注入(inject)到reserve()中。)
现在考虑我建议的替代方案:
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)
对我来说,最终结果似乎是相同的,只是减去了对 ctors/dtors 的调用。
是否存在这种替代方案会失败的情况,如果是,缺陷在哪里?
附言我认为这不是很相关,但这里是 vector
和 vector_base
类的数据成员:
// 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:
//...
};
最佳答案
这可能会失败:
memcpy()
仅当您有 POD vector 时才有效。对于所有其他类型的对象,它将失败,因为它不尊重它复制的对象的语义(复制构造)。
问题示例:
- 如果对象的构造函数设置了一些指向内部成员的内部指针,你的
memcpy()
会复制原来指针的值,不会正确更新,继续指向一段内存将被释放的区域。 - 如果对象包含
shared_ptr
,对象计数将变得不一致(memcpy()
将复制指针而不增加其引用计数,然后swap( )
会确保原来的共享指针在b中,b会被释放,这样共享指针引用计数就会递减)。
正如 T.C 在评论中指出的那样,一旦您的 vector 存储非 POD 数据,memcpy()
就会导致 UB(未定义行为)。
关于c++ - STL 中 std::vector 的 reserve() 实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34821661/