How to construct a universal object linked list in C/C ++

Source: Internet
Author: User

T. W. Burger (twburger@bigfoot.com), boss, Thomas Wolfgang burger Consulting

September 01, 2000

Have you ever done a project that requires you to save a certain number of different objects in the memory? In some cases, binary trees are the best choice, but in general, a simpler linked list is an obvious choice.

Example of a simplified Problem

The difficulty of a linked list is that you must copy the linked list processing function to process different objects, even if the logic is identical. For example:

Two linked lists with similar structures

struct Struct_Object_A
{
int a;
int b;
Struct_Object_A *next;
} OBJECT_A;
typedef struct Struct_Object_B
{
int a;
int b;
int c;
Struct_Object_B *next;
} OBJECT_B;

The two structures defined above have only a small difference. The difference between object_ B and object_a is only one integer variable. However, in the compiler's view, they are still very different. Each object stored in the linked list must be copied to add, delete, and search functions for the linked list. To solve this problem, you can use a union or structure with all three variables. The integer c is not used in all cases. This may become very complex and lead to a bad programming style.

C code solution: Virtual linked list

One of the better solutions to this problem is the virtual linked list. A virtual linked list contains only linked list pointers. Objects are stored behind the linked list structure. This is implemented in this way. First, allocate memory for the linked list node, then allocate memory for the object, and then allocate the memory to the linked list node pointer, as shown below:

An Implementation of the virtual linked list Structure

Typedef struct liststruct
{
Liststruct * next;
} List, * plist;
Plist head = NULL;
Plist addtolist (plist head, void * data, size_t datasize)
{
Plist newlist = NULL;
Void * P;
// Allocate node memory and data memory
Newlist = (plist) malloc (datasize + sizeof (list ));
// Specify a pointer for this data buffer
P = (void *) (newlist + 1 );
// Copy data
Memcpy (p, Data, datasize );
// Specify this node to the table header of the linked list.
If (head)
{
Newlist-> next = head;
}
Else
Newlist-> next = NULL;
Head = newlist;
Return head;
}

The linked list node is now built on the data value copy. This version can well process scalar values, but cannot process objects with elements allocated using malloc or new. To process these objects, the list structure must contain a general de-function pointer, which can be used to release memory (or close files) before deleting a node from the linked list and removing it, or call the close method ).

A linked list with a lift Function

Typedef void (* listnodedestructor) (void *);
Typedef struct liststruct
{
Listnodedestructor destructfunc;
Liststruct * next;
} List, * plist;
Plist addtolist (plist head, void * data, size_t datasize,
Listnodedestructor destructor)
{
Plist newlist = NULL;
Void * P;
// Allocate node memory and data memory
Newlist = (plist) malloc (datasize + sizeof (list ));
// Specify a pointer for this data buffer
P = (void *) (newlist + 1 );
// Copy data
Memcpy (p, Data, datasize );
Newlist-> destructfunc = destructor;

// Specify this node to the table header of the linked list.
If (head)
{
Newlist-> next = head;
}
Else
Newlist-> next = NULL;
Head = newlist;
Return head;
}
Void deletelist (plist head)
{
Plist next;
While (head)
{
Next = head-> next;
Head-> destructfunc (void *) Head );
Free (head );
Head = next;
}
}
Typedef struct listdatastruct
{
Lpstr P;
} List_data, * plist_data;
Void listdatadestructor (void * P)
{
// Type conversion for node pointers
Plist PL = (plist) P;
// Type conversion for data pointers
Plist_data PLD = (plist_data) (PL + 1 );
Delete PLD-> P;
}
Plist head = NULL;
Void testlist ()
{
Plist_data d = new list_data;
D-> P = new char [24];
Strcpy (D-> P, "hello ");
Head = addtolist (Head, (void *) d, sizeof (plist_data ),
Listdatadestructor );
// This object has been copied and is now deleted from the original object
Delete D;
D = new list_data;
D-> P = new char [24];
Strcpy (D-> P, "world ");
Head = addtolist (Head, (void *) d, sizeof (plist_data ),
Listdatadestructor );
Delete D;
// Release the linked list
Deletelist (head );
}

The same pointer containing the same unfunction in each linked list node seems to be a waste of memory space. This is true, but this is the case only when the linked list always contains the same object. Writing a linked list in this way allows you to place any object in any position in the linked list. Most linked list functions require that objects are always of the same type or class. The virtual linked list does not have this requirement. All it needs is a method that separates objects from each other. To achieve this, you can detect and remove the function pointer value, or add a type value before all the structures used in the linked list. Of course, if you want to write a linked list as a C ++ class, you can only set and store the pointer pointing to the unfunction once.

C ++ solution: Linked List

This solution defines the clist class as a class exported from the list structure. It processes a single storage type by storing a single value of the relief function. Note that the added getcurrentdata () function completes the mathematical conversion from the linked list node pointer to the data offset pointer.

A virtual linked list object

// Define the release function pointer
Typedef void (* listnodedestructor) (void *);
// The linked list with the function pointer removed is not added.
Typedef struct ndliststruct
{
Ndliststruct * next;
} Nd_list, * pnd_list;
// Define a linked list for processing a data type
Class clist: Public nd_list
{
Public:
Clist (listnodedestructor );
~ Clist ();
Pnd_list addtolist (void * data, size_t datasize );
Void * getcurrentdata ();
Void deletelist (pnd_list head );
PRIVATE:
Pnd_list m_headoflist;
Pnd_list m_currentnode;
Listnodedestructor m_destructfunc;
};
// Construct the linked list object with the correct starting value
Clist: clist (listnodedestructor destructor)
: M_headoflist (null), m_currentnode (null)
{
M_destructfunc = destructor;
}
// Delete the linked list after removing the object
Clist ::~ Clist ()
{
Deletelist (m_headoflist );
}
// Add a new node to the linked list
Pnd_list clist: addtolist (void * data, size_t datasize)
{
Pnd_list newlist = NULL;
Void * P;
// Allocate node memory and data memory
Newlist = (pnd_list) malloc (datasize + sizeof (nd_list ));
// Specify a pointer for this data buffer
P = (void *) (newlist + 1 );
// Copy data
Memcpy (p, Data, datasize );
// Specify this node to the table header of the linked list.
If (m_headoflist)
{
Newlist-> next = m_headoflist;
}
Else
Newlist-> next = NULL;
M_headoflist = newlist;
Return m_headoflist;
}
// Return the current node data as the void type so that the calling function can convert it to any type
Void * clist: getcurrentdata ()
{
Return (void *) (m_currentnode + 1 );
}
// Delete the allocated linked list
Void clist: deletelist (pnd_list head)
{
Pnd_list next;
While (head)
{
Next = head-> next;
M_destructfunc (void *) Head );
Free (head );
Head = next;
}
}
// Create a structure to be created and stored in the linked list
Typedef struct listdatastruct
{
Lpstr P;
} List_data, * pnd_list_data;
// Define standard release functions
Void classlistdatadestructor (void * P)
{
// Type conversion for node pointers
Pnd_list PL = (pnd_list) P;
// Type conversion for data pointers
Pnd_list_data PLD = (pnd_list_data) (PL + 1 );
Delete PLD-> P;
}
// Test the above Code
Void myclistclasstest ()
{
// Create a linked list
Clist * pa_list_of_data = new clist (classlistdatadestructor );
// Create a Data Object

Pnd_list_data d = new list_data;
D-> P = new char [24];
Strcpy (D-> P, "hello ");
// Create a local pointer pointing to the top of the linked list
Pnd_list head = NULL;
// Add some data to the linked list
Head = pa_list_of_data-> addtolist (void *) d,
Sizeof (pnd_list_data ));
// This object has been copied and is now deleted from the original object
Delete D;
// Confirm that it has been stored
Char * P = (pnd_list_data) pa_list_of_data-> getcurrentdata ()-> P;
D = new list_data;
D-> P = new char [24];
Strcpy (D-> P, "world ");
Head = pa_list_of_data-> addtolist (void *) d, sizeof (pnd_list_data ));
// This object has been copied and is now deleted from the original object
Delete D;
// Confirm that it has been stored
P = (pnd_list_data) pa_list_of_data-> getcurrentdata ()-> P;
// Delete the Linked List class. The Destructor deletes the linked list.
Delete pa_list_of_data;
}

Summary

From the previous discussion, it seems that writing a simple linked list only requires a lot of work, but this only needs to be done once. It is easy to expand this code into a C ++ class that processes sorting, search, and various other tasks, and this class can process any data object or class (in a project, it processes about 20 different objects ). You never have to rewrite this code.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.