I don't understand the last few lines here.
// Singly linked list node with freelist support
template<typename Elem> class Link {
private:
static Link<Elem>* freelist; // Reference to freelist head
public:
Elem element; // Value for this node
Link* next; // Point to next node in list
// Constructors
Link(const Elem& elemval, Link* nextval = NULL)
{ element = elemval; next = nextval; }
Link(Link* nextval = NULL) { next = nextval; }
void* operator new(size_t) { // Overloaded new operator
if (freelist == NULL) return ::new Link; // Create space
Link<Elem>* temp = freelist; // Can take from freelist
freelist = freelist->next;
return temp; // Return the link
}
// Overloaded delete operator
void operator delete(void* ptr) {
((Link<Elem>*)ptr)->next = freelist; // Put on freelist
freelist = (Link<Elem>*)ptr;
}
};
// The freelist head pointer is actually created here
template<typename Elem>
Link<Elem>* Link<Elem>::freelist = NULL;
In particular, why do we need to define a pointer to a pointer in the last line? Link<Elem>::freelist
is already a pointer, so why do we need to set another pointer to that pointer to NULL
?
Can someone clear this up for me? I'm very confused.
Distilling your example down, this is what you have:
class Link {
static Link* freelist;
}
Link* Link::freelist = NULL;
As the comment mentions, "The freelist head pointer is actually created here". The first part is a declaration of the static variable freelist
but it does not actually define it. The definition below mimics the declaration (and gives it a value). It does not add another level of pointer.
Not only the last two lines should raise questions, but the implementation of the operator new
.
Let's consider the following code:
struct S {
// ...
};
auto list = new List<S>;
Here new List<S>
will call List<S>::operator new
to allocate raw memory. It will call global ::new
, and that global ::new
will allocate memory (with ::operator new
) and construct Link
, ie S
and Link*
, in it. Then our local new
will construct Link
again at the same memory location. As a result, S
will be constructed twice at the same memory location. Depending on S
, this can lead to undefined behaviour and/or memory leaks.
Simple example:
struct S {
S() { std::cout << "ctor at " << this << '\n'; }
~S() { std::cout << "dtor at " << this << '\n'; }
};
int main() {
auto list = new Link<S>;
delete list;
}
Sample output:
ctor at 0x24b8e80
ctor at 0x24b8e80
dtor at 0x24b8e80
Declaration of static non-const member of class requires exactly one out-of-line definition. Static members do not use their class object's storage, so you have to declare and initialize its own separately.
class Link {
static Link* freelist; // declaring that such object exists
};
// Shouldn't appear in a header file to not break One Definition Rule
Link* Link::freelist = nullptr; // initialization
freelist is actually a "global" variable which could be accessed though context of class Link, eg Link::freelist
if it was public. In this particular case , it's just being shared between all instances of class object.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.