请教一个shared_ptr的问题。

rattlesnake620 2007-10-11 11:17:51
shared_ptr是怎么记住它起初得到的指针类型的?
比如
struct B{ };
shared_ptr<void> ptr(new B( ));
也能正确执行,我只能看到它有一个成员模板构造函数,但是却找不到析构函数的源码,请各位高手指点一下那两行程序的运行机制,最好能详细说一下shared_ptr是怎么记住B的类型的,谢谢。
...全文
220 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
iambic 2007-10-12
  • 打赏
  • 举报
回复
to manan_ycb:

boost/detail/shared_ptr_mnt.hpp是2004年的代码。你再看下boost/shared_ptr.hpp。
我的boost是用svn更新的,不排除可能和release版的有些出入。


不管怎样实现,我要提醒,避免使用shared_ptr<void>这样的东西。delete一个void*指针是undefined行为。
manan_ycb 2007-10-12
  • 打赏
  • 举报
回复
谢谢!这个例子是我从网上抄的,只是感到奇怪为什么没有警告的运行,我的boost库中竟然找不到那个析构函数,我原以为析构函数会直接delete px,呵呵,多谢指教了!
========================================================================================================================================
从其它指针类型转换为void*对编译器来说是认可的。
manan_ycb 2007-10-12
  • 打赏
  • 举报
回复
to 12楼的。我去boost的官方网站看了,是和我这个一样的啊。我的boost版本是1.33.1,1.34.1版本的也是这样的代码。
这个shared_ptr是在boost/detail/shared_ptr_nmt.hpp这个文件里的.
rattlesnake620 2007-10-11
  • 打赏
  • 举报
回复
我知道是void,我想问的是ptr析构的时候怎么记住他原来得到的是个B类型的指针的,不可能delete void类型吧。
iambic 2007-10-11
  • 打赏
  • 举报
回复
类型是void。你静态声明的。
rattlesnake620 2007-10-11
  • 打赏
  • 举报
回复
源码中不是有析构函数么?模板参数用void是不能记住原始类型的。如果类B中另申请了资源或内存,那么就会造成资源/内存泄露
========================================================================================================
谢谢!这个例子是我从网上抄的,只是感到奇怪为什么没有警告的运行,我的boost库中竟然找不到那个析构函数,我原以为析构函数会直接delete px,呵呵,多谢指教了!
iambic 2007-10-11
  • 打赏
  • 举报
回复
to 楼主:
shared_ptr <void> ptr (new B());


一、你把B*保存到shared_ptr<void>中,除了问题本来就是你的责任。什么叫正确处理?正确处理错误的使用算不算正确处理?写shared_ptr<void>本来就是一件没什么意义的事情。shared_ptr设计者或许可以选择禁用shared_ptr<void>。

二、当前的实现中,B的析构函数确实能够被调用。B的类型信息从shared_ptr构造函数中获取,之后转寄到pn中了。部分代码:
template<class T> class shared_ptr
{

// ...

public:

template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
{
// ...
}

// ...

// generated copy constructor, assignment, destructor are fine...

// ...

private:

T * px; // contained pointer
boost::detail::shared_count pn; // reference counter

};


shared_count pn内部有一个sp_counted_base,指向一个多态的有详细指针类型的派生类实例(如果你读过《C++设计新思维》中有关函数对象的那部分内容应该就很容易理解):
class shared_count
{
private:

sp_counted_base * pi_;

template<class Y> explicit shared_count( Y * p ): pi_( 0 )
// ...
{

pi_ = new sp_counted_impl_p<Y>( p );
}
// ...
};

sp_counted_impl_p<Y>的Y就是你用的B。
iambic 2007-10-11
  • 打赏
  • 举报
回复
to 楼上:你的boost::shared_ptr是什么版本?怎么我从boost svn trunk中得到的和你的不一样?
相比起来你的好像简陋很多。
manan_ycb 2007-10-11
  • 打赏
  • 举报
回复

namespace boost
{

template<class T> class shared_ptr
{
private:

typedef detail::atomic_count count_type;

public:

typedef T element_type;
typedef T value_type;

explicit shared_ptr(T * p = 0): px(p)
{
#ifndef BOOST_NO_EXCEPTIONS

try // prevent leak if new throws
{
pn = new count_type(1);
}
catch(...)
{
boost::checked_delete(p);
throw;
}

#else

pn = new count_type(1);

if(pn == 0)
{
boost::checked_delete(p);
boost::throw_exception(std::bad_alloc());
}

#endif
}

~shared_ptr()
{
if(--*pn == 0)
{
boost::checked_delete(px);
delete pn;
}
}

shared_ptr(shared_ptr const & r): px(r.px) // never throws
{
pn = r.pn;
++*pn;
}

shared_ptr & operator=(shared_ptr const & r)
{
shared_ptr(r).swap(*this);
return *this;
}

#ifndef BOOST_NO_AUTO_PTR

explicit shared_ptr(std::auto_ptr<T> & r)
{
pn = new count_type(1); // may throw
px = r.release(); // fix: moved here to stop leak if new throws
}

shared_ptr & operator=(std::auto_ptr<T> & r)
{
shared_ptr(r).swap(*this);
return *this;
}

#endif

void reset(T * p = 0)
{
BOOST_ASSERT(p == 0 || p != px);
shared_ptr(p).swap(*this);
}

T & operator*() const // never throws
{
BOOST_ASSERT(px != 0);
return *px;
}

T * operator->() const // never throws
{
BOOST_ASSERT(px != 0);
return px;
}

T * get() const // never throws
{
return px;
}

long use_count() const // never throws
{
return *pn;
}

bool unique() const // never throws
{
return *pn == 1;
}

void swap(shared_ptr<T> & other) // never throws
{
std::swap(px, other.px);
std::swap(pn, other.pn);
}

private:

T * px; // contained pointer
count_type * pn; // ptr to reference counter
};

源码中不是有析构函数么?模板参数用void是不能记住原始类型的。如果类B中另申请了资源或内存,那么就会造成资源/内存泄露
rattlesnake620 2007-10-11
  • 打赏
  • 举报
回复
他内部存了这个类型的,有一个类,专门存这个类型,然后delete的时候能正确删除的
================================================================
谢谢,能不能麻烦给讲的详细一些,那个源码我看不太懂。
rattlesnake620 2007-10-11
  • 打赏
  • 举报
回复
我知道是void,我想问的是ptr析构的时候怎么记住他原来得到的是个B类型的指针的,不可能delete void类型吧。
======================================
为什么不可能?是你自己非要把B类型的指针保存到shared_ptr <void >对象中的,又不是别人逼你这样做的
=============================================================================================
麻烦你看贴仔细点行不,我问的是在这种情况下shared_ptr能正确处理的原理是什么,你觉得它析构的时候会去delete void类型吗?我是想请教一下它是怎么记住它得到的原始指针是B类型的,最后去delete *B的。
晨星 2007-10-11
  • 打赏
  • 举报
回复
楼主的程序在效果上相当于:

void* p = new B();
delete p;

区别仅在于引用计数和最终的释放被shared_ptr自动化了而已。
iambic 2007-10-11
  • 打赏
  • 举报
回复
回复了,我看到了。
晨星 2007-10-11
  • 打赏
  • 举报
回复
?我没回复这个帖子?还是CSDN又出bug了?
晨星 2007-10-11
  • 打赏
  • 举报
回复
我知道是void,我想问的是ptr析构的时候怎么记住他原来得到的是个B类型的指针的,不可能delete void类型吧。
======================================
为什么不可能?是你自己非要把B类型的指针保存到shared_ptr<void>对象中的,又不是别人逼你这样做的。
Oversense 2007-10-11
  • 打赏
  • 举报
回复
他内部存了这个类型的,有一个类,专门存这个类型,然后delete的时候能正确删除的
iambic 2007-10-11
  • 打赏
  • 举报
回复

template<class T> class shared_ptr
{
// ...
template<class Y>
explicit shared_ptr( Y * p ): px( p ), pn( p )
{
boost::detail::sp_enable_shared_from_this( pn, p, p );
}
// ...
};

64,653

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧