Closed TonyChouZJU closed 9 years ago
@TonyChouZJU 你好,请问下你的 gcc
是哪个版本的呢? 我用 4.9.1 并未重现。在 VS 下试了,也未出现。比较好奇。
我比较倾向于你摘出来的这个解释( @Mooophy ),应该是 p
指向的 int
对象被释放了两次导致的。。
vs2013,没有复现。
@pezy @Mooophy 我是在linux 下使用gcc 4.8.2出现的. 同样的问题更明显的出现在练习12.13 这道题的解答为什么要加上一个{}使得它变成一个代码块呢?
int main()
{
{
auto sp = std::make_shared
return 0;
}
我之后做了一些尝试,将这个{}去掉,在delete p;加上一句比如cout<<"before main exits!"<<endl;
从结果看,对于用new来初始化的shared_ptr,
shared_ptr
我在stackoverflow上贴了一个详细的问题,希望能够讨论下http://stackoverflow.com/questions/30294604/what-if-i-delete-the-pointer-that-the-smart-pointer-is-managing
@pezy @Mooophy 二位大大所说的没有出现是指的是?你们在process函数外加上cout<<"exit main"<<endl; 可以输出exit main么?
void process(std::shared_ptr
int main()
{
std::shared_ptr
@TonyChouZJU 是的呢,可以输出的。我在 gcc 4.8.1 也试了一次,也是可以输出。
还试了在线的:http://coliru.stacked-crooked.com/a/6b991a8ead6e8975
都可以输出。。。
会发现没有输出before main exits!,在delete p后立马报错double free.
这个问题书上早就说明,对 get()
返回的指针进行 delete 是不被允许的,请见:
Caution: Smart Pointer Pitfalls Smart pointers can provide safety and convenience for handling dynamically allocated memory only when they are used properly. To use smart pointers correctly, we must adhere to a set of conventions:
- Don’t use the same built-in pointer value to initialize (or reset) more than one smart pointer.
- Don’t delete the pointer returned from get().
- Don’t use get() to initialize or reset another smart pointer.
- If you use a pointer returned by get(), remember that the pointer will become invalid when the last corresponding smart pointer goes away.
- If you use a smart pointer to manage a resource other than memory allocated by new, remember to pass a deleter
@pezy 囧 写错了new出来的是可以输出的,我想问的是make_shared
int main()
{
std::shared_ptr p=make_shared
@TonyChouZJU
原来如此,那我可能知道问题在哪了。
你清楚 std::shared_ptr<int> p(new int(100));
与 make_shared<int>(100)
的区别不?
前者其实分配了两次内存,一次为匿名对象分配,一次为引用计数分配。后者却仅有引用计数分配。
引用计数分配的内存,是由智能指针自身管理的,当 use_count 变成 0,则回收内存。你给 process
传参的时候,又弄了一个新的局部智能指针来管理同一份内存。当该局部智能指针的 use_count 变成 0 的时候,它是要回收所管理的内存的,可是显然这份内存还有一个管理者:外部的智能指针 p
。造成了内存错误(double free)。
如果采用第一种方式,外部智能指针 p
实际管理着两份内存,一是为匿名对象所分配的,另一份是智能指针引用计数所管理的。所以此刻你调用 p->use_count()
会得到 1,因为你只看的到 1 份计数。同样的,在 process
结束的时候,删掉了一份内存,但此刻不会有内存错误,因为 p
其实还管理着一份内存,只不过他对其一无所知,你用 *p
访问其值的时候,会发现是一个随机值。而继续用 p->use_count()
依然会得到 1,这乍一看很诡异,但你结合上面内存分配两次这个事实,就比较好理解了。
综上,请避免使用第一种方式为智能指针初始化,尽量使用 make_shared<int>
的方式。
Reference:
从程序的运行上来看,运行后,的确会有double free or corruption的错误。
从这个解释上来看,是
main
函数退出时,p
原来指向的内存被再次释放导致的。 但是,如果测试程序如果在process(std::shared_ptr<int>(p.get()));
后加上一句比如cout<<"exit main"<<endl;
会发现并没有输出exit main
这句话就已经报错 double free or corruption。 同样,如果 gdb 一下,这个错误也是process
一返回就报错的。shared_ptr<int> p(new int(42));
和share_ptr<int>(p.get())
是两个独立的shared_ptr
指向相同的内存,process
退出时会销毁函数的局部变量,指向的内存int(42)
同样被释放,感觉没有double free啊 不知道问题出在了哪里??