使用 std::allocator 取消分配
Deallocating with std::allocator
我一直在尝试编写自己的 STL 容器实现以供练习,但在重新分配元素时遇到了一些问题。我创建了一个简单的 Array
class ,它基本上是标准 C++ 数组的包装器。我一直在尝试实现的重大变化是允许在数组没有默认构造函数的情况下对其进行初始化(我知道 Vectors 可以做到这一点,但我想练习实现它)。由于此功能,我无法使用 new
,因此我决定让容器像标准 STL 容器一样使用分配器。 Array
看起来有点像这样:
template<class T, class A = std::allocator<T>> class Array {
public:
// STL definitions and iterators...
/// initializes an array of size elements with all elements being
/// default constructed.
Array(const size_type &size) : Array(size, T()) {
}
/// Initializes an array of size elements with all elements being
/// copies of the fill element.
Array(const size_type &size, const T &fill) {
this->allocator = A(); // Get allocator from template
this->size = this->max_size = size;
// Allocate data array and copy the fill element into each
// index of the array.
this->data = this->allocator.allocate(size);
this->allocator.construct(this->data, fill);
}
/// Deletes the array and all of its elements.
~Array() {
// deallocate using the allocator
this->allocator.deallocate(this->data, this->size);
}
// other things...
}
为了测试我的数组,我创建了一个简单的测试 class,它只是跟踪它存在的实例数,每次构造函数或复制构造函数被称为 instance_count
的变量时递增,每次调用析构函数时,变量都会递减。然后我编写了以下方法来断言 Array
正在正确创建和销毁元素:
void testArray() {
for (int i = 1; i < 100; i++) {
std::cout << TestObject::instance_count << ", "; // should always == 0
Array<TestObject> testArray(i); // Create array of I elements
std::cout << TestObject::instance_count << ", "; // should == i
}
}
我的预期输出是 0, 1, 0, 2, 0, 3, 0, 4...
,这意味着在范围的开头不存在 TestObjects,然后在数组中分配正确数量的对象,并在范围的末尾销毁它们。相反,我得到了 0, 1, 1, 2, 2, 3, 3, 4, 4...
的输出,这表明由于某种原因元素没有被正确销毁。这就像元素仅在分配新元素时才被释放,但这不是我想要的行为。此外,在 for
循环之外,instance_count
等于 100,这意味着即使没有更多的 Array
实例,仍有对象剩余。有人可以向我解释为什么 std::allocator
没有正确清理元素吗?
因为您并没有销毁对象,只是释放了它们占用的内存。分配器将allocation/deallocation(使用allocate
和deallocate
)和construction/destruction(使用construct
和destroy
)的概念分开。
要创建对象,您正在调用 allocate
和 construct
。
要销毁对象,您需要调用 destroy
然后 deallocate
。
我一直在尝试编写自己的 STL 容器实现以供练习,但在重新分配元素时遇到了一些问题。我创建了一个简单的 Array
class ,它基本上是标准 C++ 数组的包装器。我一直在尝试实现的重大变化是允许在数组没有默认构造函数的情况下对其进行初始化(我知道 Vectors 可以做到这一点,但我想练习实现它)。由于此功能,我无法使用 new
,因此我决定让容器像标准 STL 容器一样使用分配器。 Array
看起来有点像这样:
template<class T, class A = std::allocator<T>> class Array {
public:
// STL definitions and iterators...
/// initializes an array of size elements with all elements being
/// default constructed.
Array(const size_type &size) : Array(size, T()) {
}
/// Initializes an array of size elements with all elements being
/// copies of the fill element.
Array(const size_type &size, const T &fill) {
this->allocator = A(); // Get allocator from template
this->size = this->max_size = size;
// Allocate data array and copy the fill element into each
// index of the array.
this->data = this->allocator.allocate(size);
this->allocator.construct(this->data, fill);
}
/// Deletes the array and all of its elements.
~Array() {
// deallocate using the allocator
this->allocator.deallocate(this->data, this->size);
}
// other things...
}
为了测试我的数组,我创建了一个简单的测试 class,它只是跟踪它存在的实例数,每次构造函数或复制构造函数被称为 instance_count
的变量时递增,每次调用析构函数时,变量都会递减。然后我编写了以下方法来断言 Array
正在正确创建和销毁元素:
void testArray() {
for (int i = 1; i < 100; i++) {
std::cout << TestObject::instance_count << ", "; // should always == 0
Array<TestObject> testArray(i); // Create array of I elements
std::cout << TestObject::instance_count << ", "; // should == i
}
}
我的预期输出是 0, 1, 0, 2, 0, 3, 0, 4...
,这意味着在范围的开头不存在 TestObjects,然后在数组中分配正确数量的对象,并在范围的末尾销毁它们。相反,我得到了 0, 1, 1, 2, 2, 3, 3, 4, 4...
的输出,这表明由于某种原因元素没有被正确销毁。这就像元素仅在分配新元素时才被释放,但这不是我想要的行为。此外,在 for
循环之外,instance_count
等于 100,这意味着即使没有更多的 Array
实例,仍有对象剩余。有人可以向我解释为什么 std::allocator
没有正确清理元素吗?
因为您并没有销毁对象,只是释放了它们占用的内存。分配器将allocation/deallocation(使用allocate
和deallocate
)和construction/destruction(使用construct
和destroy
)的概念分开。
要创建对象,您正在调用 allocate
和 construct
。
要销毁对象,您需要调用 destroy
然后 deallocate
。