reserve() 在 STL 中实现 std::vector
reserve() Implementation for std::vector in STL
考虑一下 std::vector::reserve() 的实现,来自"The C++ Programming Language, 4th ed., Bjarne Stroustrup"一书:
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 进行了一次调用(如果元素的类具有基数,或者如果类或其基具有带有 ctors 的数据成员,则可能会触发更多此类调用)。(在书中,for-loop实际上是一个单独的函数,但为了简单起见,我在这里将其注入到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/dtor 的调用。
是否存在这种替代方案会失败的情况,如果是这样,缺陷在哪里?
附言我认为这不太相关,但以下是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:
//...
};
这可能会失败:
-
只有当你有一个 POD 向量时,
memcpy()
才会起作用。 -
对于所有其他类型的对象,它将失败,因为它不尊重它复制的对象的语义(复制构造)。
问题示例:
- 如果对象的构造函数设置了一些指向内部成员的内部指针,则
memcpy()
将复制原始指针的值,该值将不会正确更新,并继续指向将要释放的内存区域。 - 如果对象包含
shared_ptr
,则对象计数将变得不一致(memcpy()
将复制指针而不增加其引用计数,则swap()
将确保原始共享指针将在 b 中,这将被释放,以便共享指针引用计数将递减)。
正如 T.C 在评论中指出的那样,一旦您的向量存储了非 POD 数据,memcpy()
就会产生 UB(未定义的行为)。
相关文章:
- C++标准是否允许<double>在没有开销的情况下实现 std::可选
- glibcxx STL 在实现 std::valarray::sum() 时是否不正确?
- 在 x86 上实现 std::atomic_thread_fence(std::memory_order_seq_cst
- 尝试实现std::tie和std::tuple的小版本
- 在实现 std::vector 时,我必须拥有 end() 的"end"指针吗?
- 如何正确实现 std::all_of 函数来验证字符串的一部分?
- 如何为向量实现 std::erase ?
- 如何实现std ::何时_any而不进行轮询
- 如何正确安全地实现 std::array 的C++算术运算符
- 与自定义命名空间一起使用时实现 std::error_category、名称解析问题
- 如何为模板类实现std ::哈希
- 为什么标准库不以无锁的方式为 8 字节以下的结构实现 std::atomic?
- 为什么 MSVC 在实现 std::bitset::count 时不使用 __popcnt?
- 实现 std::tuple 的详细信息
- 如何实现std :: set(红色/黑色树)前迭代
- 以C 标准的方式实现STD :: Malloc
- 如何为自定义模板化迭代器实现 std::d istance()
- 如何实现 std::map::查找包含两个结构'Pos'结构的比较逻辑,每个结构包含 x 和 y 坐标
- 实现 std::vector::p ush_back 强异常安全
- 是否可以实现std ::移动和清除功能