vector如何在减小尺寸后不破坏元素两次?
How does vector not destroy element twice after reducing its size?
出于测试目的,我试图创建自己的向量 class,但我无法弄清楚 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;
}
输出是
A constructed (1)
A constructed (2)
A constructed (3)
A destroyed (1)
Vector resized
A destroyed (2)
A destroyed (3)
调用vec.resize(2)
时,第三个元素被销毁,但vector的容量仍然是3。那么当vec
被销毁时,它的所有元素包括已经被销毁的元素都应该被销毁. std::vector
怎么知道他已经破坏了那个元素?我怎样才能在我的向量中实现它 class?
容量和尺寸之间存在差异。给定一个 std::vector<T> v;
向量已经为 v.capacity()
个元素分配了内存。但只有前 v.size()
个地方包含构造的 T
个对象。
因此,v.reserve(1000)
在空向量上不会调用任何额外的构造函数。 vec.resize(2)
在你的例子中破坏了最后一个元素,vec[2]
现在是内存中的一个空位置,但内存仍然由 vec
拥有。
我认为你的分配看起来像 buffer = new T[newSize];
。这不是 std::vector
的工作方式,它不允许 Ts
没有默认构造函数。也许你没有意识到这一点,但是每当你获得一块内存时,它已经包含对象,让它成为 T x;
甚至 new double[newSize];
其中 returns 一个双精度数组(尽管它们的构造函数是空的)。
在 C++ 中只有一种方法可以获得可用的未初始化内存,即分配 chars
。这是由于 strict aliasing rule. There also (is|must be) a way how to call a constructor explicitly on this memory i.e. how to create an object there. The vector uses something called placement new 正是这样做的。然后分配只是 buffer = new char[newSize*sizeof(T)];
,它不创建任何对象。
对象的生命周期由这个放置新运算符和对析构函数的显式调用管理。
emplace_back(arg1,arg2)
可以实现为 {new(buffer + size) T(arg1,arg2);++size;}
。请注意,简单地执行 buffer[size]=T(arg1,arg2);
是不正确的和 UB。 operator=
预计左侧尺寸 (*this
) 已经存在。
如果你想销毁一个对象,例如pop_back
,你必须做
buffer[size].~T();--size;
。这是您应该显式调用析构函数的极少数地方之一。
简单的答案是 vector 在内部管理构造函数和析构函数调用,通常通过使用 inplace operator new 和 operator delete 方法。
弹出一个元素后,它立即被分解,虽然内存仍然可用,并且可能仍然包含一些剩余值,但std::vector本身知道哪些元素仍然需要删除,并且不会再次调用析构函数。
When vec.resize(2)
is called, the third element is destroyed, but the vector's capacity is still 3.
是的。 capacity
是向量的内部数组在物理上可以容纳多少个元素。 size
是该数组中实际有效的元素数量。缩小 size
根本不会影响 capacity
。
Then when vec
is destroyed, all of its elements including the one already destroyed should be destroyed.
之前被销毁并从数组中移除的第三个元素不会再次被销毁。只有 size
个元素被破坏,而不是 capacity
个元素,就像你想的那样。
How does std::vector
know that he has already destroyed that element?
它分别跟踪size
和capacity
。当一个元素从数组中移除时,它后面的元素每个都在数组中向下移动 1 个槽位,并且 size
递减。
出于测试目的,我试图创建自己的向量 class,但我无法弄清楚 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;
}
输出是
A constructed (1)
A constructed (2)
A constructed (3)
A destroyed (1)
Vector resized
A destroyed (2)
A destroyed (3)
调用vec.resize(2)
时,第三个元素被销毁,但vector的容量仍然是3。那么当vec
被销毁时,它的所有元素包括已经被销毁的元素都应该被销毁. std::vector
怎么知道他已经破坏了那个元素?我怎样才能在我的向量中实现它 class?
容量和尺寸之间存在差异。给定一个 std::vector<T> v;
向量已经为 v.capacity()
个元素分配了内存。但只有前 v.size()
个地方包含构造的 T
个对象。
因此,v.reserve(1000)
在空向量上不会调用任何额外的构造函数。 vec.resize(2)
在你的例子中破坏了最后一个元素,vec[2]
现在是内存中的一个空位置,但内存仍然由 vec
拥有。
我认为你的分配看起来像 buffer = new T[newSize];
。这不是 std::vector
的工作方式,它不允许 Ts
没有默认构造函数。也许你没有意识到这一点,但是每当你获得一块内存时,它已经包含对象,让它成为 T x;
甚至 new double[newSize];
其中 returns 一个双精度数组(尽管它们的构造函数是空的)。
在 C++ 中只有一种方法可以获得可用的未初始化内存,即分配 chars
。这是由于 strict aliasing rule. There also (is|must be) a way how to call a constructor explicitly on this memory i.e. how to create an object there. The vector uses something called placement new 正是这样做的。然后分配只是 buffer = new char[newSize*sizeof(T)];
,它不创建任何对象。
对象的生命周期由这个放置新运算符和对析构函数的显式调用管理。
emplace_back(arg1,arg2)
可以实现为 {new(buffer + size) T(arg1,arg2);++size;}
。请注意,简单地执行 buffer[size]=T(arg1,arg2);
是不正确的和 UB。 operator=
预计左侧尺寸 (*this
) 已经存在。
如果你想销毁一个对象,例如pop_back
,你必须做
buffer[size].~T();--size;
。这是您应该显式调用析构函数的极少数地方之一。
简单的答案是 vector 在内部管理构造函数和析构函数调用,通常通过使用 inplace operator new 和 operator delete 方法。
弹出一个元素后,它立即被分解,虽然内存仍然可用,并且可能仍然包含一些剩余值,但std::vector本身知道哪些元素仍然需要删除,并且不会再次调用析构函数。
When
vec.resize(2)
is called, the third element is destroyed, but the vector's capacity is still 3.
是的。 capacity
是向量的内部数组在物理上可以容纳多少个元素。 size
是该数组中实际有效的元素数量。缩小 size
根本不会影响 capacity
。
Then when
vec
is destroyed, all of its elements including the one already destroyed should be destroyed.
之前被销毁并从数组中移除的第三个元素不会再次被销毁。只有 size
个元素被破坏,而不是 capacity
个元素,就像你想的那样。
How does
std::vector
know that he has already destroyed that element?
它分别跟踪size
和capacity
。当一个元素从数组中移除时,它后面的元素每个都在数组中向下移动 1 个槽位,并且 size
递减。