如何在c ++中创建没有动态内存分配作为模板的链表

问题描述

我开始研究《 C ++动手系统编程》一书 并且我尝试使用没有动态内存分配的模板创建以下链接列表。但是每次我尝试构建链表时,除了必须为new分配内存外,别无他法-我还要如何创建一个新节点?

据我所知,作者可以替换使用c ++模板创建新节点的需求,因为分配动态内存被认为很慢。 到目前为止,这是否不意味着在编译时使用静态内存分配或数组或宏编程,而在运行时具有相同的灵活性?还是误会?

我缺少什么?首先感谢您有关如何在不使用c ++模板动态分配内存的情况下如何动态创建链接列表的提示

“这些类型的链表(和其他数据结构)在Internet上有很多实现,它们提供了链表的通用实现,而无需动态分配数据。” 我在C ++中找不到任何东西:(

”在前面的示例中,我们不仅能够创建没有宏或动态分配的链接列表(以及使用void *指针所带来的所有问题),但是我们也能够封装功能,提供更简洁的实现和用户API。”

那是我试图做的,但是我困惑的每种方式都必须动态分配内存:


template<typename T>
class MyLinkedList
{
    struct node
    {
        T data;
        node* next = nullptr;
    };

private:
    node m_head;

public:


    void setData(T value)
    {
        if(m_head.next == nullptr){
        m_head.data = value;
        }
    }

    T getData()
    {
        return m_head.data;
    }


};

int main()
{
    MyLinkedList<int> list;
    list.setData(4);
    std::cout << list.getData() << std::endl;



    return 0;
}

本书中有关C ++模板的全文: Hands-On System Programming in C++

C ++中使用的模板

模板编程通常是被低估,被误解的加法 对于没有足够功劳的C ++。大多数程序员需要看 只不过尝试创建通用链接列表以 了解原因。

C ++模板使您能够定义代码 无需提前定义类型信息。

在C语言中创建链接列表的一种方法是使用指针和动态 内存分配,如以下简单示例所示:

struct node  {
    void *data;
    node next; };

void add_data(node *n,void *val);

在前面的示例中,我们使用void将数据存储在链接列表中 *。如何使用它的一个示例如下:

node head; add_data(&head,malloc(sizeof(int)));
*(int*)head.data = 42;

方法存在一些问题:

这种类型的链表显然不是类型安全的。数据的使用与数据的分配是完全无关的,要求程序员使用此链接列表来无错误地管理所有这些。 节点和数据都需要动态内存分配。如前所述,内存分配缓慢,因为它们 需要系统调用。 通常,此代码难以阅读且笨拙。

创建通用链接列表的另一种方法是使用宏。那里 这些类型的链表的几种实现(以及其他 数据结构)漂浮在互联网上,从而提供 链表的通用实现,无需 动态分配数据。这些宏为用户提供了一种方法 定义链表将在编译时管理的数据类型。

除了可靠性以外,这些方法的问题还在于 实现使用宏以某种方式实现模板编程 那远远不够优雅。换句话说,添加解决方案 C的通用数据结构是使用C的宏语言手动 实现模板编程。程序员会更好 只是使用C ++模板。

在C ++中,无需链接即可创建像链表这样的数据结构 必须声明链表正在管理的类型,直到 声明如下:

template<typename T> class mylinked_list {
    struct node 
    {
        T data;
        node *next;
    };

public:

    ...

private:

    node m_head; };

在前面的示例中,我们不仅能够创建链接列表 没有宏或动态分配(以及所有出现的问题) 使用void *指针),但我们也能够封装 功能,提供更简洁的实现和用户API。

关于模板编程的一个常抱怨是 它生成代码量。大多数代码膨胀通常来自模板 源于编程错误。例如,程序员可能不会 意识到整数和无符号整数不是同一类型, 使用模板时导致代码膨胀(作为 每种类型都会创建。)

除了该问题之外,使用宏也会产生相同的结果 代码膨胀。天下没有免费的午餐。如果要避免使用 动态分配和类型转换,同时仍提供通用 算法,您必须为每个算法创建一个算法实例 您打算使用的类型。如果可靠性是您的目标,则允许 编译器生成确保程序执行所需的代码 适当地胜过了缺点。

我缺少什么?首先感谢您有关如何在不使用c ++模板动态分配内存的情况下如何动态创建链接列表的提示

解决方法

除了必须分配新的内存外,别无其他方法-我还要如何创建一个新节点?

您可以声明一个变量。或者,您可以使用placement-new将动态对象创建到非动态内存中。

这是使用节点变量的链表的最小示例:

template<class T>
struct node
{
    T data;
    node* next = nullptr;
};

// some function
node<int> n3{3,nullptr};
node<int> n2{2,&n3};
node<int> n1{1,&n2};

为动态对象重用非动态存储要复杂得多。我推荐一种结构化的方法,将预先存在的实现(例如std::list)与自定义分配器结合使用。