Помоги мне переписать мой код, используя умные указатели:
template <typename T>
struct DL_node
{
    T value;
    DL_node<T>* prev;
    DL_node<T>* next;

    DL_node(T data) : value(data), prev(nullptr), next(nullptr) {}
};

template <typename T>
class PersistentDoublyLinkedList
{
private:
    std::vector<DL_node<T>*> versions{}; // fat-node; vector to store all versions

    int current_version{};

    // helper function to make a copy of a list
    // takes the head of copied list
    // returns a new list that is a copy of a given list
    DL_node<T>* copyList(DL_node<T>* root)
    {
        if (!root) { return nullptr; }

        DL_node<T>* new_head = new DL_node<T>(root->value); // make a copy of a root node
        DL_node<T>* current = root->next; // temp node to iterate in original
        DL_node<T>* new_current = new_head; // temp node to iterate in copied

        while (current)
        {
            new_current->next = new DL_node<T>(current->value); // connect temp node with new copied next node
            new_current->next->prev = new_current; // connect copied next node with temp node
            new_current = new_current->next; // go to the next node in copied list
            current = current->next; // go to the next node in original list
        }
        return new_head;
    }

    // helper function to print a list 
    // takes a head of list to print
    void printList(DL_node<T>* root)
    {
        DL_node<T>* current = root; // temp node
        std::cout << "{";
        while (current)
        {
            std::cout << "'" << current->value << "'";
            if (current->next)
            {
                std::cout << ", ";
            }
            current = current->next; // go to the next node
        }
        std::cout << "}";
    }

    // helper function to get a value from a specific index and version
    T getValue(int version_idx, int idx)
    {
        DL_node<T>* current = versions[version_idx];
        //T value{};
        int i{};

        while (i < idx)
        {
            current = current->next;
            i++;
        }

        return current->value;
    }

public:
    // Constructor 
    // takes an array and its size
    // creates a doubly linked list from a given array and its size
    PersistentDoublyLinkedList(T* arr, int size)
    {
        if (size <= 0) { return; }
        
        DL_node<T>* head = new DL_node<T>(arr[0]); // head of the list with first element as a value
        DL_node<T>* current = head; // temp node to iterate

        // Creation of the list from [1...size-1]
        for (int i = 1; i < size; ++i)
        {
            current->next = new DL_node<T>(arr[i]); // create a next node with next value and connect with temp node
            current->next->prev = current; // connect next node with current temp node
            current = current->next; // go to the next node
        }

        versions.push_back(head); // save a new version

        current_version = 0;
    }

    // Method to add a new version of doubly linked list
    // takes an index of a version you want to change;
    // index of element to change and a new value
    //  
    void addVersion(int root_position, int change_index, T new_value)
    {
        // Error checking
        if (root_position < 0 || root_position >= versions.size())
        {
            std::cout << "Invalid root position!" << std::endl;
            return;
        }

        DL_node<T>* root = versions[root_position]; // head of the node we want to change
        DL_node<T>* new_head = copyList(root); // head of the copied list

        DL_node<T>* current = new_head; // temp node

        // Find a node to change
        for (int i = 0; current && i < change_index; ++i)
        {
            current = current->next;
        }

        if (!current)
        {
            std::cout << "Invalid change index!" << std::endl;
            return;
        }

        current->value = new_value; // change value in found node
        versions.push_back(new_head); // add a new version

        current_version++;
    }

    // Method to make UNDO-action
    void undo()
    {
        if (current_version <= 0)
        {
            std::cout << "No actions to undo!" << std::endl;
            return;
        }

        current_version--;
        versions.push_back(versions[current_version]);
    }

    // Method to make REDO-action
    void redo()
    {
        if (current_version >= versions.size() - 1) {
            std::cout << "No actions to redo!" << std::endl;
            return;
        }

        current_version++;  // Переход к следующей версии
        versions.push_back(versions[current_version]);
    }

    // Method to print all versions
    void printAllVersions()
    {
        for (size_t i = 0; i < versions.size(); i++)
        {
            std::cout << "Version [" << i << "]:\t";
            printList(versions[i]);
            std::cout << std::endl;
        }
    }

    // Destructor
    ~PersistentDoublyLinkedList()
    {
        for (auto head : versions) // for each version
        {
            DL_node<T>* current = head; // temp node
            while (current)
            {
                DL_node<T>* next = current->next; // temp next node
                delete current; // clear memory
                current = next; // change pointer
            }
        }
    }
};