问题的引入:
const char* getFunc()
{
string str;
// Do something
return str.c_str(); // Error,Dangling Pointer
}
对于上面的代码会产生悬空指针,或者说野指针。str.c_str()返回的一个指针是string内部自己维护的,由string负责new和delete。当返回str.c_str()过后,局部变量str解栈,析构掉,自己内部的char*资源释放掉,而外部根据getFunc引用的资源就已经不在了。
像上面类似的问题还有一些类似的
比如根据一个函数返回的string临时变量,然后直接取.c_str()
string getStr();
...
const char* c_str = getStr().c_str(); // Error,Dangling Pointer
对于string和c string。 string是对c string的封转,string内部必然存储有一个指针,这个指针指向实际的c string资源。这个c string资源是可变长的,或者说是动态的char数组,而这个资源的维护由string来控制,尽管string的实现版本差异,有的实现是引用计数,而有的没有,但注意的一点就是,他是资源生命期的维护者,要直接的使用一个string内部的资源(const char*),那么就必须保证这个string对象在使用期间是有效的。
在实际使用中,应尽量避免string和c string的交叉使用,并尽量使用string,像第二种情况就可以避免;能const reference就传const reference,上面的第一个情况,如果返回为const reference,编译器会报返回局部变量的warning。指针尽量放在底层的使用。
扩展
在实际应用中,经常会遇到将一个指针保存到一个指针变量中使用,而这个是野指针的一个根源,因为当你保存得到一个指针,那么这个指针是否有效,将由你来决定,但是很多时候你却不具有这个指针指向资源的控制。当这个资源实际的控制者释放了资源,但是在外部保存的指针却得不到这个事件而变成无效指针(NULL),他就成了野指针,但是使用的时候他仍然是有效的指针(Non-NULL)。
所以在保存一个指针的时候,应该看看提供这个指针的一方是否能够保证你使用的这段时间内是有效的,如果不能保证,就不要将这个指针保存,而是在每次使用的时候,调用提供者的gettter,并检测资源有效性。
像上面的情况,是可以根据这个经验规则来避免的。当然,指针和引用,能用引用就用引用。
PS :
string getStr();
...
const char* c_str = getStr().c_str(); // Error,Dangling Pointer
在这个例子中,如果有这样的函数
void func(const char* c_str)
{
// Do something
}
...
func(getStr().c_str()); // Any problem ?
这段代码有问题吗?getStr()返回的临时变量还在吗?^ ^
阅读(1248) | 评论(0) | 转发(0) |