“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 A
和class 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是完全构造的!!