F
Francesco S. Carta
Hi there,
in order to get a better grip on the stuff about "operator new", "new
operator", "placement new" and so forth I went back to the relevant
sections of TC++PL and of the FAQ, then I've implemented a simple Vector
template trying to follow the implementation of std::vector that I found
in my implementation (ehm... OK, you know what I mean despite that
repetition).
So, among other things, I've created allocate(), deallocate(), create()
and destroy() private methods within my template, and everything went
fine, more or less.
The destroy() function consists of just this:
void destroy(value_type* ptr) {
ptr->~value_type();
}
....where value_type is the type parameter of my template (well, a
typedef of it).
I've created an "item" struct and I added the various ctor, cctor,
assignment and dtor to it.
Then I instantiated the template with something like this:
Vector<item> vec(10);
....I fiddled with some other operations (push_back(), reserve(), clear()
etc) and I run the program to verify that the various methods of "item",
dtor included, were being called the right number of times and at the
right time.
At some point I tested it with a fundamental type:
Vector<int> vec(10);
....and the template instantiation went fine, the program compiled and
ran as expected.
But then I thought: wait, I am calling the equivalent of "ptr->~int()"
within my destroy(), but if I write it directly, say something like this:
int* pi = new int;
pi->~int();
....then the compiler - as I expected - rejects it.
My conclusion is that the template mechanism is able to understand that
I'm going to do something useless with fundamental types and simply
ignores the "ptr->~value_type()" line when instantiating the template
with "value_type == some fundamental type".
Any comment or further insight on the above?
Sooner or later I'll post here the complete implementation of my Vector
to get some advice (and some corrections, very likely), but in the mean
time I'm most concerned with the basic storage management internals that
I'm pasting here below, so please have a look and point out any wrong or
silly thing I could be doing:
value_type* allocate(size_t n) {
return
reinterpret_cast<value_type*> (
new char[sizeof(value_type) * n]
);
}
void deallocate(void* ptr) {
delete[] reinterpret_cast<char*>(ptr);
}
value_type* create(void* ptr) {
return reinterpret_cast<value_type*>(new(ptr) value_type());
}
value_type* create(void* ptr, const value_type& t) {
return reinterpret_cast<value_type*>(new(ptr) value_type(t));
}
void destroy(value_type* ptr) {
ptr->~value_type();
}
Thank you very much for your attention.
in order to get a better grip on the stuff about "operator new", "new
operator", "placement new" and so forth I went back to the relevant
sections of TC++PL and of the FAQ, then I've implemented a simple Vector
template trying to follow the implementation of std::vector that I found
in my implementation (ehm... OK, you know what I mean despite that
repetition).
So, among other things, I've created allocate(), deallocate(), create()
and destroy() private methods within my template, and everything went
fine, more or less.
The destroy() function consists of just this:
void destroy(value_type* ptr) {
ptr->~value_type();
}
....where value_type is the type parameter of my template (well, a
typedef of it).
I've created an "item" struct and I added the various ctor, cctor,
assignment and dtor to it.
Then I instantiated the template with something like this:
Vector<item> vec(10);
....I fiddled with some other operations (push_back(), reserve(), clear()
etc) and I run the program to verify that the various methods of "item",
dtor included, were being called the right number of times and at the
right time.
At some point I tested it with a fundamental type:
Vector<int> vec(10);
....and the template instantiation went fine, the program compiled and
ran as expected.
But then I thought: wait, I am calling the equivalent of "ptr->~int()"
within my destroy(), but if I write it directly, say something like this:
int* pi = new int;
pi->~int();
....then the compiler - as I expected - rejects it.
My conclusion is that the template mechanism is able to understand that
I'm going to do something useless with fundamental types and simply
ignores the "ptr->~value_type()" line when instantiating the template
with "value_type == some fundamental type".
Any comment or further insight on the above?
Sooner or later I'll post here the complete implementation of my Vector
to get some advice (and some corrections, very likely), but in the mean
time I'm most concerned with the basic storage management internals that
I'm pasting here below, so please have a look and point out any wrong or
silly thing I could be doing:
value_type* allocate(size_t n) {
return
reinterpret_cast<value_type*> (
new char[sizeof(value_type) * n]
);
}
void deallocate(void* ptr) {
delete[] reinterpret_cast<char*>(ptr);
}
value_type* create(void* ptr) {
return reinterpret_cast<value_type*>(new(ptr) value_type());
}
value_type* create(void* ptr, const value_type& t) {
return reinterpret_cast<value_type*>(new(ptr) value_type(t));
}
void destroy(value_type* ptr) {
ptr->~value_type();
}
Thank you very much for your attention.