1. 程式人生 > >放棄了std::list,自己實現了一個簡單的list

放棄了std::list,自己實現了一個簡單的list

原因

在專案中前人使用了std::list來做一個佇列式,支援頭或者尾的push操作。使用場景是視訊的錄製:
生產者:從攝像頭採集資料,然後push_front到佇列頭,如果超過了最大限制,則pop_back佇列尾的元素,實現丟幀操作
消費者:從佇列裡面back拿到楨,然後pop_back刪除末尾楨。
所有的list的操作均加入了互斥鎖。理論上應該是沒有多執行緒訪問的問題的。然而在線上表現卻在back拿資料的時候有極少數的Crash。在拿資料前我還用empty方法判斷肯定不為空的。只能認為是list內部實現可能有問題。也有可能是自己使用姿勢不對吧。能力有限,看std::list的實現也看不出什麼問題。在看原始碼的過程中,發現stl::list的size()的實現居然是O(n)複雜度,搜了下原因是為了O(1)的去實現transfer方法,便於做sort, merge等操作。基於這些問題,我決定還是自己寫一個類似的資料結構,出了問題也好修復。於是就寫了如下雙向連結串列。

//
// Created by tao on 2018/3/1.
//

#pragma once

#include <atomic>
#define EXCEPTION_EMPTY_LIST 1
template<typename T>
struct Node {
    T _data;
    Node<T> *_next;
    Node<T> *_prev;
};

template<typename T>
class SimpleList {
private:
    Node<T> *m_pHead;
    Node<T> *m_pTail;
    size_t m_iSize;
public
: SimpleList() : m_pHead(nullptr), m_pTail(nullptr), m_iSize(0) {} void push_back(T x); void push_front(T x); T back() throw(int); T front(); void pop_back(); void pop_front(); inline int size() { return m_iSize; } inline
bool empty() { return m_iSize == 0; } ~SimpleList() { Node<T> *cur = m_pHead; while (cur != nullptr) { Node<T> *next = cur->_next; delete cur; cur = next; if (cur == nullptr) { break; } } } }; template<typename T> void SimpleList<T>::push_back(T x) { Node<T> *pNewNode = new Node<T>[sizeof(Node<T>)]; pNewNode->_data = x; pNewNode->_next = nullptr; pNewNode->_prev = nullptr; if (m_pHead == nullptr) { m_pHead = pNewNode; m_pHead->_prev = nullptr; m_pHead->_next = nullptr; m_pTail = m_pHead; } else { Node<T> *pCurrentNode = m_pTail; pCurrentNode->_next = pNewNode; pNewNode->_prev = pCurrentNode; m_pTail = pNewNode; } m_iSize++; } template<typename T> T SimpleList<T>::back() throw(int) { if (m_pTail) { return m_pTail->_data; } throw EXCEPTION_EMPTY_LIST; } template<typename T> T SimpleList<T>::front() { if (m_pHead) { return m_pHead->_data; } throw EXCEPTION_EMPTY_LIST; } template<typename T> void SimpleList<T>::pop_back() { if (m_pTail) { if (m_pTail->_prev == nullptr) { delete m_pTail; m_pTail = nullptr; m_pHead = nullptr; } else { Node<T> *del = m_pTail; m_pTail = m_pTail->_prev; m_pTail->_next = nullptr; delete del; del = nullptr; } m_iSize--; } } template<typename T> void SimpleList<T>::push_front(T x) { Node<T> *pNewNode = new Node<T>[sizeof(Node<T>)]; pNewNode->_data = x; pNewNode->_next = m_pHead; pNewNode->_prev = nullptr; if (m_pHead != nullptr) { m_pHead->_prev = pNewNode; } m_pHead = pNewNode; if (m_pTail == nullptr) { m_pTail = m_pHead; m_pTail->_prev = nullptr; m_pTail->_next = nullptr; } m_iSize++; } template<typename T> void SimpleList<T>::pop_front() { if (m_pHead != nullptr) { if (m_pHead->_next == nullptr) { delete m_pHead; m_pHead = nullptr; m_pTail = nullptr; } else { Node<T> *del = m_pHead; m_pHead = m_pHead->_next; m_pHead->_prev = nullptr; delete del; del = nullptr; } m_iSize--; } }