手撕代码
1、阻塞队列/线程安全队列
实现:
注意问题:
1、防止虚假唤醒的lambda表达式需要传入this,也就是调用变量
2、lambda表达式的函数体不可以使用自己写的判断队列满或者空函数
template <typename T>
class block_queue
{
public:
block_queue(int max_size = 1000)
{
if (max_size <= 0)
{
exit(-1);
}
m_max_size = max_size;
m_size = 0;
m_array = new T[m_max_size];
m_front = -1;;
m_back = -1;
}
block_queue(const block_queue&) = delete;
~block_queue()
{
std::unique_lock<std::mutex> ulk(m_mutex);
if (m_array != NULL)
delete[] m_array;
}
/*
往队列添加元素,需要将所有使用队列的线程先唤醒
当有元素push进队列,相当于生产者生产了一个元素
若当前没有线程等待条件变量,则唤醒无意义
*/
bool push(const T &item)
{
std::unique_lock<std::mutex> ulk(m_mutex);
/*
while (m_size >= m_max_size)
m_cond.wait(ulk);
*/
m_cond.wait(ulk, [this]() {
return m_size < m_max_size;
});
//将新增数据放在循环数组的对应位置
m_back = (m_back + 1) % m_max_size;
m_array[m_back] = item;
m_size++;
m_cond.notify_all();
return true;
}
//pop时,如果当前队列没有元素,将会等待条件变量
bool pop(T &item)
{
std::unique_lock<std::mutex> ulk(m_mutex);
/*
//多个消费者的时候,这里要是用while而不是if
while (m_size <= 0)
m_cond.wait(guard);
*/
m_cond.wait(ulk, [this]() {
return m_size > 0;
});
//取出队列首的元素,这里需要理解一下,使用循环数组模拟的队列
m_front = (m_front + 1) % m_max_size;
item = m_array[m_front];
m_size--;
m_cond.notify_all();
return true;
}
//返回队首元素
bool front(T &value)
{
std::unique_lock<std::mutex> ulk(m_mutex);
if (0 == m_size)
{
//ulk.unlock();
return false;
}
value = m_array[m_front];
m_mutex.unlock();
return true;
}
//返回队尾元素
bool back(T &value)
{
std::unique_lock<std::mutex> ulk(m_mutex);
if (0 == m_size)
{
//ulk.unlock();
return false;
}
value = m_array[m_back];
return true;
}
int size()
{
int tmp = 0;
std::unique_lock<std::mutex> ulk(m_mutex);
tmp = m_size;
return tmp;
}
int max_size()
{
int tmp = 0;
std::unique_lock<std::mutex> ulk(m_mutex);
tmp = m_max_size;
return tmp;
}
//判断队列是否满了
bool full()
{
std::unique_lock<std::mutex> ulk(m_mutex);
if (m_size >= m_max_size)
{
return true;
}
return false;
}
//判断队列是否为空
bool empty()
{
std::unique_lock<std::mutex> ulk(m_mutex);
if (0 == m_size)
{
return true;
}
return false;
}
private:
std::mutex m_mutex;
std::condition_variable m_cond;
int m_max_size;
int m_size;
T* m_array;
int m_front;
int m_back;
};
2、unique_ptr智能指针
C++11中又引入了unique_ptr,他的实现思路非常简单粗暴,就是防拷贝,既然多个智能指针指向同一资源会导致问题,那就干脆不让你这样做,这样问题自然也就解决了。C++11中也是非常推荐使用这种智能指针,因为其比起shared_ptr和auto_ptr来说较为稳定,不会导致严重的错误但是其也存在缺陷,就是在需要拷贝的场景下他没有办法使用。
实现:
1、禁止拷贝构造
2、进制复制构造
3、可以实现移动语义
1 template<typename T>
2 class My_unique_ptr
3 {
4 private:
5 T* _ptr;
6 public:
7 My_unique_ptr(const T* ptr) : _ptr(ptr) {}
8 My_unique_ptr(const My_unique_ptr<T>&) = delete;
9 My_unique_ptr& operator=(const My_unique_ptr<T>&) = delete;
10 ~My_unique_ptr()
11 {
12 if (_ptr)
13 {
14 delete _ptr;
15 _ptr = nullptr;
16 }
17 }
18 T& operator*()
19 {
20 return *_ptr;
21 }
22 T* operator->()
23 {
24 return _ptr;
25 }
26 };
3、实现shared_ptr智能指针
为了弥补unique_ptr不能拷贝的缺陷,C++11中还引入了shared_ptr,他的实现思路是引用计数,通过计数的方式来实现多个智能指针共同管理一个资源。shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
相较于unique_ptr,它弥补了不能拷贝的缺陷,但是因为需要保证多线程并发时的线程安全问题,所以对于计数操作要进行加锁,所以导致其效率相对来说会低一些,并且还存在循环引用的问题,所以大部分情况下如果不需要进行拷贝,都会使用unique_ptr,需要拷贝时才使用shared_ptr.
实现:
1、引用计数实现
2、独特地析构函数
3、允许拷贝构造
4、允许复制构造(注意:需要先释放掉原来所指向地对象)
1 template<typename T> 2 class mysharedptr { 3 private: 4 T* _ptr; 5 int* _pcount; 6 std::mutex* _pmtx; 7 //加锁保证线程安全 8 void add_ref_count() { 9 _pmtx->lock(); 10 ++(*_pcount); 11 _pmtx->unlock(); 12 } 13 void release() { 14 bool flag = false; 15 _pmtx->lock(); 16 if (--(*_pcount) == 0) { 17 if (_ptr) { 18 delete _ptr; 19 _ptr = nullptr; 20 } 21 delete _pcount; 22 _pcount = nullptr; 23 flag = true; 24 } 25 _pmtx->unlock(); 26 if (flag) { 27 delete _pmtx; 28 _pmtx = nullptr; 29 } 30 } 31 32 public: 33 mysharedptr(T* ptr) : _ptr(ptr), _pcount(new int(1)), _pmtx(new std::mutex) {} 34 mysharedptr(mysharedptr<T>& sp) : _ptr(sp._ptr), _pcount(sp._pcount), _pmtx(sp._pmtx){ 35 add_ref_count(); 36 } 37 mysharedptr<T>& operator=(mysharedptr<T>& sp) { 38 if (this != &sp ) { 39 release(); //自己原来所指向的对象的引用计数减1 40 _ptr = sp._ptr; 41 _pcount = sp._pcount; 42 _pmtx = sp._pmtx; 43 44 add_ref_count(); 45 } 46 return *this; 47 } 48 ~mysharedptr() { 49 release(); 50 } 51 52 T& operator*() { 53 return *_ptr; 54 } 55 T* operator->() { 56 return _ptr; 57 } 58 59 T* get() const { 60 return _ptr; 61 } 62 size_t use_count() const { 63 return *_pcount; 64 } 65 };
四、数字字符串相加(lc415)
1 string addStrings(string num1, string num2) {
2 int len1 = num1.size(), len2 = num2.size();
3 int len = max(len1, len2);
4 vector<int> reg(len, 0);
5 int i1 = len1 - 1, i2 = len2 - 1, index = len - 1, pre = 0;
6 string ans;
7 while (i1 >= 0 || i2 >= 0 || pre != 0)
8 {
9 int x = i1 >= 0 ? num1[i1] - '0' : 0;
10 int y = i2 >= 0 ? num2[i2] - '0' : 0;
11 int cur = x + y + pre;
12 ans.push_back('0' + cur % 10);
13 pre = cur / 10;
14 i1--;
15 i2--;
16 }
17 reverse(ans.begin(), ans.end());
18 return ans;
19 }
本文来自博客园,作者:Mr-xxx,转载请注明原文链接:https://www.cnblogs.com/MrLiuZF/p/15078857.html