ARTS-WEEK5

"ARTS打卡记录"

Posted by Simon on June 28, 2020

“Better code, better life. ”

ARTS打卡第五周

Algorithm

[题目] :https://leetcode-cn.com/problems/remove-duplicate-node-lcci/

[题解]

class Solution {
public:
    ListNode *removeDuplicateNodes(ListNode *head) {
        if (head == nullptr) {
            return nullptr;
        }
        unordered_map<int, int> v;
        v[head->val]++;
        ListNode *cur;
        cur = head;
        while (cur->next) {
            if (v[cur->next->val]) {
                cur->next = cur->next->next;
            } else {
                v[cur->next->val]++;
                cur = cur->next;
            }
        }
        return head;
    }
};

Review

[文章链接] :http://www.wangafu.net/~nickm/libevent-book/Ref5_evutil.html

[笔记] :

本片文章讲的是Libevent提供的一些辅助函数。

定时器操作

操作宏

#define evutil_timeradd(tvp, uvp, vvp) /* 将前两个参数的和的结果储存在第三个变量中 */

#define evutil_timersub(tvp, uvp, vvp) /* 将前两个参数的差的结果储存在第三个变量中 */

#define evutil_timerclear(tvp) /* 将一个timeval置为0 */

#define evutil_timerisset(tvp) /* 如果tvp为0返回false,否则返回true */

#define evutil_timercmp(tvp, uvp, cmp) /* 比较两个时间戳 */

函数

//将tv设置为当前时间,tz未使用
int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);

Example:

struct timeval tv1, tv2, tv3;

/* Set tv1 = 5.5 seconds */
tv1.tv_sec = 5; tv1.tv_usec = 500*1000;

/* Set tv2 = now */
evutil_gettimeofday(&tv2, NULL);

/* Set tv3 = 5.5 seconds in the future */
evutil_timeradd(&tv1, &tv2, &tv3);

/* all 3 should print true */
if (evutil_timercmp(&tv1, &tv1, ==))  /* == "If tv1 == tv1" */
   puts("5.5 sec == 5.5 sec");
if (evutil_timercmp(&tv3, &tv2, >=))  /* == "If tv3 >= tv2" */
   puts("The future is after the present.");
if (evutil_timercmp(&tv1, &tv2, <))   /* == "If tv1 < tv2" */
   puts("It is no longer the past.");
Socket操作

由于Windows下对Berkeley sockets API的支持并不是很友好,所以Libevent提供了一系列的替代函数。

//close socket
int evutil_closesocket(evutil_socket_t s);
//仅仅在2.0.5-alpha之后的版本支持,之前的版本使用EVUTIL_CLOSESOCKET宏
#define EVUTIL_CLOSESOCKET(s) evutil_closesocket(s)

上面的宏和函数,在Unix下封装了close(),在Windows下封装了closesocket()

#define EVUTIL_SOCKET_ERROR() /* 返回一个全局的错误码,他是上一个socket的操作结果 */
#define EVUTIL_SET_SOCKET_ERROR(errcode) /* 设置当前socket的错误码 */
#define evutil_socket_geterror(sock) /* 返回一个全局的错误码,他是上一个socket的操作结果 */
#define evutil_socket_error_to_string(errcode) /* 类似strerror(),返回错误码代表的错误信息 */
//创建一个新的socket并且设置为非阻塞IO
int evutil_make_socket_nonblocking(evutil_socket_t sock);
//socket关闭后,立即对另外一个链接可用
int evutil_make_listen_socket_reuseable(evutil_socket_t sock);
//设置该socket为调用exec()后即close,类似UNIX中的FD_CLOEXEC
int evutil_make_socket_closeonexec(evutil_socket_t sock);
//等于UNIX下的socketpair(),创建两个建立连接的socket,
int evutil_socketpair(int family, int type, int protocol,
        evutil_socket_t sv[2]);
字符串操作
//类似strtol,但是返回一个int64类型
ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
//功能等于标准snprintf和vsnprintf,如果缓冲区的长度足够,则返回写道缓冲区中的字节数
int evutil_snprintf(char *buf, size_t buflen, const char *format, ...);
int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
//功能上等于strcasecmp和strncasecmp,会把str当作ASCII码,而不会考虑当前系统的语言
//2.0.3-alpha版本后支持
int evutil_ascii_strcasecmp(const char *str1, const char *str2);
int evutil_ascii_strncasecmp(const char *str1, const char *str2, size_t n);

Tips

一个enable_shared_from_this导致的问题

本周工作上遇到了一个coredump,排查下来发现是误用了enable_shared_from_this导致,具体情况是这样的。

我需要两个类class Aclass B,他们互相持有对方,很自然,我想到了智能指针,并且是一个shared_ptr一个weak_ptr,所以有了如下代码:

文件a.h

#include "b.h"

class A : public std::enable_shared_from_this<A>{
public:
    A(B* b){
        _b_ptr.reset(b);
        b.Register(this);
    }
private:
	std::shared_ptr<B> _b_ptr;    
}

文件b.h

class A;

class B{
public:
    B()=default;
    void Register(A* a){
        _a_ptr= a->shared_from_this();
    }
    
private:
    std::weak_ptr<A> _a_ptr;
}

文件main.cpp

int main(){
    auto a = std::make_shared<A>(new B);
}

以上代码没有编译错误,但运行后core了。

这里需要注意的有以下几点:

  • 在调用shared_from_this时,要保证当前this指针已被一个shared_ptr所持有
  • 两个类互相持有时,需要用到不完全声明
  • 两个只能指针一定只能有一个时shared_ptr,否则会导致循环引用

以上该注意的地方都注意了,那到底哪里出了问题呢?

【问题】在A类的构造函数中,当前this指针还没有构造完成,就将它暴露给了B类!!

正确的做法是在类A中新增一个Register方法做注册,保证对外暴露的this是完全构造的!!

Share

Redis数据结构-链表