您所描述的方法不仅与C++兼容,而且与其
(大部分)子集语言C也兼容。学习开发C风格的链表是介绍低级编程技术(如手动内存管理)的好方法,但通常不是现代C++开发的最佳实践。
下面,我实现了四种变化来管理C++中的项目列表。
raw_pointer_demo
使用与您相同的方法 - 需要使用原始指针进行手动内存管理。在此,C++仅用于语法糖,否则使用的方法与C语言兼容。
- 在
shared_pointer_demo
中,列表管理仍然是手动完成的,但是内存管理是自动的(不使用原始指针)。这与您在Java中体验到的非常相似。
std_list_demo
使用标准库list
容器。这显示了如果依赖于现有库而不是自己编写代码,事情会变得更加容易。
std_vector_demo
使用标准库vector
容器。这将列表存储在单个连续的内存分配中。换句话说,没有指向各个元素的指针。对于某些相当极端的情况,这可能会变得非常低效。但是,对于典型情况,这是C++中列表管理的推荐最佳实践。
值得注意的是:所有这些方法中,只有
raw_pointer_demo
实际上需要显式销毁列表以避免“泄漏”内存。当容器超出范围时(在函数结束时),其他三种方法将
自动销毁列表及其内容。重点是:如果选择使用可用的高级工具开发程序,则C++在这方面可以非常类似于Java。
#include <iostream>
#include <algorithm>
#include <string>
#include <list>
#include <vector>
#include <memory>
using std::cerr;
void raw_pointer_demo()
{
cerr << "\n" << "raw_pointer_demo()..." << "\n";
struct Node
{
Node(int data, Node *next) : data(data), next(next) {}
int data;
Node *next;
};
Node * items = 0;
items = new Node(1,items);
items = new Node(7,items);
items = new Node(3,items);
items = new Node(9,items);
for (Node *i = items; i != 0; i = i->next)
cerr << (i==items?"":", ") << i->data;
cerr << "\n";
while (items) {
Node *temp = items;
items = items->next;
delete temp;
}
}
raw_pointer_demo()...
9, 3, 7, 1
void shared_pointer_demo()
{
cerr << "\n" << "shared_pointer_demo()..." << "\n";
struct Node;
typedef std::shared_ptr<Node> Node_reference;
struct Node
{
Node(int data, std::shared_ptr<Node> next ) : data(data), next(next) {}
int data;
Node_reference next;
};
Node_reference items = 0;
items.reset( new Node(1,items) );
items.reset( new Node(7,items) );
items.reset( new Node(3,items) );
items.reset( new Node(9,items) );
for (Node_reference i = items; i != 0; i = i->next)
cerr << (i==items?"":", ") << i->data;
cerr<<"\n";
while (items)
items = items->next;
}
shared_pointer_demo()...
9, 3, 7, 1
template< typename C >
void show(std::string const & msg, C const & container)
{
cerr << msg;
bool first = true;
for ( int i : container )
cerr << (first?" ":", ") << i, first = false;
cerr<<"\n";
}
void std_list_demo()
{
cerr << "\n" << "std_list_demo()..." << "\n";
std::list<int> items = { 9, 3, 7, 1 };
show( "A: ", items );
items.insert(std::find( items.begin(), items.end(), 3), 8);
show("B: ", items);
items.sort();
show( "C: ", items);
items.erase(std::find(items.begin(), items.end(), 7));
show("D: ", items);
items.clear();
show("E: ", items);
}
std_list_demo()...
A: 9, 3, 7, 1
B: 9, 8, 3, 7, 1
C: 1, 3, 7, 8, 9
D: 1, 3, 8, 9
E:
void std_vector_demo()
{
cerr << "\n" << "std_vector_demo()..." << "\n";
std::vector<int> items = { 9, 3, 7, 1 };
show( "A: ", items );
items.insert(std::find(items.begin(), items.end(), 3), 8);
show( "B: ", items );
sort(items.begin(), items.end());
show("C: ", items);
items.erase( std::find( items.begin(), items.end(), 7 ) );
show("D: ", items);
items.clear();
show("E: ", items);
}
std_vector_demo()...
A: 9, 3, 7, 1
B: 9, 8, 3, 7, 1
C: 1, 3, 7, 8, 9
D: 1, 3, 8, 9
E:
int main()
{
raw_pointer_demo();
shared_pointer_demo();
std_list_demo();
std_vector_demo();
}
Node m_next
并不是对节点的引用,而是存储整个Node
本身的空间。 - Brian Cain