简体   繁体   English

向量减小大小后如何不破坏元素两次?

[英]How does vector not destroy element twice after reducing its size?

For testing purposes, I was trying to create my own vector class, and I couldn't figure out how std::vector size reduction works. 出于测试目的,我试图创建自己的向量类,但无法弄清楚std::vector大小缩减的工作原理。

class A
{
    A()
    { std::cout << "A constructed") << std::endl; }
    ~A()
    { std::cout << "A destroyed") << std::endl; }
}

main()
{
    std::vector<A> vec(3, A());
    vec.resize(2);
    std::cout << "vector resized" << std::endl;
}

Output is 输出是

A constructed       (1)
A constructed       (2)
A constructed       (3)
A destroyed         (1)
Vector resized
A destroyed         (2)
A destroyed         (3)

When vec.resize(2) is called, the third element is destroyed, but the vector's capacity is still 3. Then when vec is destroyed, all of its elements including the one already destroyed should be destroyed. vec.resize(2) ,第三个元素被销毁,但向量的容量仍为3。然后,当vec被销毁时,其所有元素(包括已销毁的元素)都应被销毁。 How does std::vector know that he has already destroyed that element? std::vector如何知道他已经销毁了该元素? How can I implement that in my vector class? 如何在向量类中实现它?

There's a difference between capacity and size. 容量和大小之间有区别。 Given a std::vector<T> v; 给定一个std::vector<T> v; The vector has allocated memory for v.capacity() elements. 该向量已为v.capacity()元素分配了内存。 But only in the first v.size() places contain constructed T objects. 但仅在第一个v.size()位置包含构造的T对象。

So, v.reserve(1000) on an empty vector won't call any additional constructors. 因此,在空向量上的v.reserve(1000)不会调用任何其他构造函数。 vec.resize(2) in your example destroys the last element and vec[2] is now an empty place in memory, but memory still owned by the vec . 您的示例中的vec.resize(2)破坏了最后一个元素,并且vec[2]现在在内存中为空,但内存仍由vec拥有。

I think your allocation looks like buffer = new T[newSize]; 我认为您的分配看起来像buffer = new T[newSize]; . That is not how std::vector works which would not allow Ts that do not have default constructors. 这不是std::vector工作方式,不允许没有默认构造函数的Ts Maybe you did not realize this, but whenever you obtain a piece of memory, it already contains objects, let it be T x; 也许您没有意识到这一点,但是每当获得一块内存时,它已经包含对象,将其设为T x; or even new double[newSize]; 甚至是new double[newSize]; which returns an array of doubles (although their constructors are empty). 它返回一个双精度数组(尽管它们的构造函数为空)。

There is only one way to get usable uninitialized memory in C++, which is to allocate chars . 在C ++中只有一种获得可用的未初始化内存的方法,即分配chars This is due to the strict aliasing rule. 这是由于严格的别名规则。 There also (is|must be) a way how to call a constructor explicitly on this memory ie how to create an object there. 还有(必须是)如何在此内存上显式调用构造函数的方法,即如何在该内存上创建对象。 The vector uses something called placement new which does precisely that. 向量使用称为“ 新放置”的东西来精确地做到这一点。 The allocation is then simply buffer = new char[newSize*sizeof(T)]; 然后,分配就是buffer = new char[newSize*sizeof(T)]; which creates no objects whatsoever. 不会创建任何对象。

The lifetime of the objects is managed by this placement new operator and explicit calls to destructors. 对象的生存期由此放置位置new运算符和对析构函数的显式调用来管理。 emplace_back(arg1,arg2) could be implemented as {new(buffer + size) T(arg1,arg2);++size;} . emplace_back(arg1,arg2)可以实现为{new(buffer + size) T(arg1,arg2);++size;} Note that simply doing buffer[size]=T(arg1,arg2); 请注意,只需执行buffer[size]=T(arg1,arg2); is incorrect and UB. 和UB不正确。 operator= expects that the left size( *this ) already exists. operator=期望左边的大小( *this )已经存在。

If you want to destroy an object with eg pop_back , you must do buffer[size].~T();--size; 如果要使用pop_back破坏对象,则必须执行buffer[size].~T();--size; pop_back buffer[size].~T();--size; . This is one of the very few places where you should call the destructor explicitly. 这是应显式调用析构函数的极少数地方之一。

The simple answer is that vector internally manages constructor and destructor calls, often by using inplace operator new and operator delete methods. 简单的答案是,vector通常通过使用inplace运算符new和operator delete方法在内部管理构造函数和析构函数调用。

Having popped an element, it is immediately descructed, and while the memory is still available, and may still contain some remnant values, std::vector itself knows which elements still need to be deleted, and won't call the destructor again. 弹出元素后,将立即对其进行销毁,并且在内存仍然可用且可能仍包含一些剩余值的情况下,std :: vector本身知道哪些元素仍需要删除,因此不会再次调用析构函数。

When vec.resize(2) is called, the third element is destroyed, but the vector's capacity is still 3. vec.resize(2) ,第三个元素被破坏,但向量的容量仍为3。

Yes. 是。 The capacity is how many elements the vector's internal array can physically hold. capacity是向量的内部数组可以物理容纳多少个元素。 The size is how many elements in that array are actually valid. size是该数组中实际有效的元素数。 Shrinking the size does not affect the capacity at all. 缩小size根本不影响capacity

Then when vec is destroyed, all of its elements including the one already destroyed should be destroyed. 然后,当vec被销毁时,其所有元素,包括已经销毁的元素都应被销毁。

The 3rd element that was previously destroyed and removed from the array is not destroyed again. 先前已销毁并从数组中删除的第三个元素不会再次销毁。 Only size number of elements are destroyed, not capacity number of elements, like you are thinking. 就像您正在思考的那样,仅破坏size的元素数目,而不破坏capacity的元素数目。

How does std::vector know that he has already destroyed that element? std::vector如何知道他已经销毁了该元素?

It tracks the size and capacity separately. 它分别跟踪sizecapacity When an element is removed from the array, the elements that follow it are moved down the array by 1 slot each, and the size is decremented. 从数组中删除一个元素时,其后的元素将分别在数组中向下移动1个插槽,并且size会减小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 向量是否必须存储两次大小? - Does a vector have to store the size twice? 如何得出函数内部向量的大小? (向量通过指向其第一个元素的指针传递) - How to derive the size of vector inside a function? (the vector is passed by a pointer to its first element) shrink_to_fit是减少`std :: vector`到其大小的容量的正确方法吗? - Is shrink_to_fit the proper way of reducing the capacity a `std::vector` to its size? 在没有默认构造函数的情况下减小 std::vector 的大小 - Reducing the size of a std::vector without a default constructor C ++ std :: container(向量)如何存储其内部(元素地址,按索引访问)? - How does a C++ std::container (vector) store its internals (element address, access by index)? 向量如何在将元素的引用推回给自身的同时如何工作? - How does vector work while pushing back a reference of its element to itself? vector :: size()如何在常量时间内返回向量的大小? - How does the vector::size() returns size of the vector in constant time? std :: vector如何破坏它的对象? - How does std::vector destruct its objects? 向量元素大小 - Vector Element Size std::vector size()-1 是否总是给出最后一个元素的索引? - Does std::vector size()-1 ALWAYS give the index of the last element?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM