放棄了std::list,自己實現了一個簡單的list
阿新 • • 發佈:2018-12-25
原因
在專案中前人使用了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--;
}
}