golang中container/list包中的坑
来源:互联网 发布:ubuntu挂起唤醒快捷键 编辑:程序博客网 时间:2024/05/24 07:23
golang中list包用法可以参看http://blog.csdn.net/chenbaoke/article/details/42780895
但是list包中大部分对于e *Element进行操作的元素都可能会导致程序崩溃,其根本原因是e是一个Element类型的指针,当然其也可能为nil,但是golang中list包中函数没有对其进行是否为nil的检查,变默认其非nil进行操作,所以这种情况下,便可能出现程序崩溃。
1.举个简单例子,Remove()函数
package mainimport ("container/list""fmt")func main() {l := list.New()l.PushBack(1)fmt.Println(l.Front().Value) //1value := l.Remove(l.Front())fmt.Println(value) //1value1 := l.Remove(l.Front()) //panic: runtime error: invalid memory address or nil pointer dereferencefmt.Println(value1)}从程序中可以直观的看出程序崩溃,原因是list中只有1个元素,但是要删除2个元素。但是再进一步查看一下原因,便会得出如下结果。
golang中Front()函数实现如下
func (l *List) Front() *Element { if l.len == 0 { return nil } return l.root.next}由此可见,当第一次删除之后。list的长度变为0,此时在调用l.Remove(l.Front()),其中l.Front()返回的是一个nil。
接下来再看golang中Remove()函数实现,该函数并没有判定e是否为nil,变直接默认其为非nil,直接对其进行e.list或者e.Value取值操作。当e为nil时,这两个操作都将会造成程序崩溃,这也就是为什么上面程序会崩溃的原因。
func (l *List) Remove(e *Element) interface{} {if e.list == l {// if e.list == l, l must have been initialized when e was inserted// in l or l == nil (e is a zero Element) and l.remove will crashl.remove(e)}return e.Value}
2.(l *list)PushBackList(other *list)该函数用于将other list中元素添加在l list的后面。基本实现思想是取出other中所有元素,将其顺次挂载在l列表中,但是golang中实现有问题,代码如下。
func (l *List) PushBackList(other *List) {l.lazyInit()for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() {l.insertValue(e.Value, l.root.prev)}}其具体思想是首先获取other的长度n,然后循环n次取出其元素将其插入l中。问题就出现在循环n次,如果在这个过程中other的元素变化的话,例如其中有些元素被删除了,这就导致e的指针可能为nil,此时再利用e.Value取值,程序便会崩溃。如下所示。
package mainimport ("container/list""runtime")func main() {runtime.GOMAXPROCS(8)l := list.New()ls := list.New()for i := 0; i < 10000; i++ {ls.PushBack(i)}go ls.Remove(l.Back())l.PushBackList(ls) //invalid memory address or nil pointer dereference}如程序中所示,再讲ls中元素添加到l过程中,如果ls中元素减少,程序便会崩溃。原因如上面分析。
建议:
在golang中如果对与list的操作只有串行操作,则只需要注意检查元素指针是否为nil便可避免程序崩溃,如果程序中会并发处理list中元素,建议对list进行加写锁(全局锁),然后再操作。注意,读写锁无法保证并行处理list时程序的安全性。
0 0
- golang中container/list包中的坑
- golang中container/list包中的坑
- golang中container/list包用法
- golang中container/list包用法
- golang中container/list包用法
- golang中container/ring包用法
- golang中container/heap包用法
- golang 集合包阅读container包
- Golang中的闭包
- container包中的三个数据类型(-)
- golang中解决tcp传输中的粘包问题
- golang 中的闭包用法
- golang 包中的init调用
- golang中的rpc包用法
- golang 中的http包详解
- golang 中的http包详解
- golang list坑
- golang中bytes包用法
- 数据结构实验之链表一:顺序建立链表
- HDU 5074 Hatsune Miku(简单二维dp)
- C# 多线程编程,传参,接受返回值
- typedef & #define的问题
- 事事皆有机缘,不争、不抢、不露。
- golang中container/list包中的坑
- SQL Server触发器
- error LNK2001: unresolved external symbol __imp_closesocket-VS2012
- CentOS 6.5的服务器忘记了root密码后解决方案
- java(jdk1.8)与sqlserver2008的连接
- 数据结构实验之链表七:单链表中重复元素的删除
- JAVA使用多播套接字实现群聊室(局域网)
- C语言执行Linux的shell命令并获得返回值
- 【我的OpenCV】第一篇 环境配置