为什么我的 C++11 分配器的 dtor 被调用了两次?
Why is my C++11 allocator's dtor called twice?
我编写了我自己的基本 c++11 分配器来分解它,看看它是如何工作的。大部分事情进展顺利,但由于某种原因,我的 dtor 被调用了两次。现在这不是问题,但我可以想象一个场景,有状态分配器在第二次调用 dtor 时尝试取消引用 nullptr,所以我很好奇这是否是预期的行为,如果是,有没有办法避免它?
代码如下:
#include<iostream>
#include<vector>
#include<new>
using std::vector;
using std::cout;
using std::endl;
using __gnu_cxx::ptrdiff_t;
template<typename elem_t>
struct myAlloc {
typedef elem_t value_type;
typedef elem_t * pointer;
typedef const elem_t * const_pointer;
typedef elem_t & reference;
typedef const elem_t & const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template<typename other_elem_t>
struct rebind {
typedef myAlloc<other_elem_t> other;
};
myAlloc() {
cout << "constructing myAlloc" << endl;
}
~myAlloc() {
cout << "destructing myAlloc" << endl;
}
pointer address(reference x) const {
cout << "myAlloc retrieving address" << endl;
return &x;
}
const_pointer address(const_reference x) const {
cout << "myAlloc retrieving address of x" << endl;
return &x;
}
pointer allocate(size_type n, const void * hint = 0) {
cout << "myAlloc allocating n elem_t's" << endl;
pointer retval = (pointer)malloc(n * sizeof(value_type));
if (retval == nullptr)
throw std::bad_alloc();
return retval;
}
void deallocate(pointer p, size_type n) {
cout << "myAlloc deallocating n elem_t's" << endl;
free(p);
}
size_type max_size() const throw() {
return -1;
}
void construct(pointer p, const_reference val) {
cout << "Constructing an elem_t 'val' at address p" << endl;
new ((void*)p) value_type (val);
}
void destroy(pointer p) {
cout << "Destroying the elem_t at address p" << endl;
p->~value_type();
}
};
void test() {
cout << "creating vec" << endl;
vector<int, myAlloc<int> > myvec = {1, 2, 3, 4, 5};
cout << "done creating vec" << endl;
}
int main() {
test();
cout << "main" << endl;
}
这是输出:
creating vec
constructing myAlloc
myAlloc allocating n elem_t's
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
destructing myAlloc
done creating vec
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
myAlloc deallocating n elem_t's
destructing myAlloc
main
我的猜测是分配器在使用时在本地构造,并在分配完对象后立即销毁。但是尽管分配器被破坏,我们还是调用了 destroy
和 deallocate
函数。为什么要这样实现?分配完成后立即销毁分配器有什么用?在一般情况下,在解除分配后调用成员函数如何不会破坏事情?
答案已发布在评论中。分配器构造两次,一次用于分配,一次用于释放。谢谢@T.C。用于解决方案和@ivaigult 用于实现
我编写了我自己的基本 c++11 分配器来分解它,看看它是如何工作的。大部分事情进展顺利,但由于某种原因,我的 dtor 被调用了两次。现在这不是问题,但我可以想象一个场景,有状态分配器在第二次调用 dtor 时尝试取消引用 nullptr,所以我很好奇这是否是预期的行为,如果是,有没有办法避免它?
代码如下:
#include<iostream>
#include<vector>
#include<new>
using std::vector;
using std::cout;
using std::endl;
using __gnu_cxx::ptrdiff_t;
template<typename elem_t>
struct myAlloc {
typedef elem_t value_type;
typedef elem_t * pointer;
typedef const elem_t * const_pointer;
typedef elem_t & reference;
typedef const elem_t & const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
template<typename other_elem_t>
struct rebind {
typedef myAlloc<other_elem_t> other;
};
myAlloc() {
cout << "constructing myAlloc" << endl;
}
~myAlloc() {
cout << "destructing myAlloc" << endl;
}
pointer address(reference x) const {
cout << "myAlloc retrieving address" << endl;
return &x;
}
const_pointer address(const_reference x) const {
cout << "myAlloc retrieving address of x" << endl;
return &x;
}
pointer allocate(size_type n, const void * hint = 0) {
cout << "myAlloc allocating n elem_t's" << endl;
pointer retval = (pointer)malloc(n * sizeof(value_type));
if (retval == nullptr)
throw std::bad_alloc();
return retval;
}
void deallocate(pointer p, size_type n) {
cout << "myAlloc deallocating n elem_t's" << endl;
free(p);
}
size_type max_size() const throw() {
return -1;
}
void construct(pointer p, const_reference val) {
cout << "Constructing an elem_t 'val' at address p" << endl;
new ((void*)p) value_type (val);
}
void destroy(pointer p) {
cout << "Destroying the elem_t at address p" << endl;
p->~value_type();
}
};
void test() {
cout << "creating vec" << endl;
vector<int, myAlloc<int> > myvec = {1, 2, 3, 4, 5};
cout << "done creating vec" << endl;
}
int main() {
test();
cout << "main" << endl;
}
这是输出:
creating vec
constructing myAlloc
myAlloc allocating n elem_t's
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
Constructing an elem_t 'val' at address p
destructing myAlloc
done creating vec
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
Destroying the elem_t at address p
myAlloc deallocating n elem_t's
destructing myAlloc
main
我的猜测是分配器在使用时在本地构造,并在分配完对象后立即销毁。但是尽管分配器被破坏,我们还是调用了 destroy
和 deallocate
函数。为什么要这样实现?分配完成后立即销毁分配器有什么用?在一般情况下,在解除分配后调用成员函数如何不会破坏事情?
答案已发布在评论中。分配器构造两次,一次用于分配,一次用于释放。谢谢@T.C。用于解决方案和@ivaigult 用于实现