| hh942111 回复于:2004-04-20 16:25:39
|
难道不能用auto_ptr对象作为list的元素吗?不可能吧!请用过类似方法的同志帮忙讲解一下如何实现
|
| whyglinux 回复于:2004-04-20 17:55:27
|
在使用 auto_ptr 的时候,有三点要注意的事项:
1. 在函数参数中不要使用引用传递 auto_ptr。因为这样做的结果是不确定的:实参 auto_ptr 可能失去所有权,也可能不失去所有权。
2. 对于 const auto_ptr 或者 const auto_ptr& (引用) 不能再进行所有权的转移。因为所有权丢失相当于改变了原来的 const auto_ptr 对象,这与 const 的定义是矛盾的。
3. auto_ptr 不能作为容器类的元素使用。因为 auto_ptr 不符合对容器类元素的一个最基本的要求:元素的拷贝或者赋值操作不能改变源对象。auto_ptr 做不到这一点。
list 的成员函数 push_back() 的原型定义为:void push_back (const T& x);。
根据规则 1,建议你这个函数的实参不能是 auto_ptr 类型的。但即使是 auto_ptr 类型,也还是合法的。
根据规则 2,你的 ptr 虽然能够传递给虚参 x ,但是,把 x 拷贝给 list 类元素的操作是非法的(会导致编译错误)。因为 x 是 const auto_ptr,违背了规则 2。
根据规则 3,你不能用auto_ptr对象作为list类的元素。
重新规划你的设计吧:用普通指针 list<test*>(缺点是要手工释放内存)或者直接用 list<test>。
|
| hh942111 回复于:2004-04-20 18:29:11
|
刚刚才找了一些资料研究了一下,知道了问题的缘由,回来就看到whyglinux的精彩回帖!真是感谢。不知whyglinux 兄可否留个联系方法(qq or msn or email),今后有什么难解的问题还想多请教 !
|
| hh942111 回复于:2004-04-21 08:54:48
|
针对上面我们讨论的这个list与auto_ptr的问题!我想再跟大家继续讨论一下,对上面的例子程序而言,test是一个很小的类,实现的拷贝构造函数也就不存在效率问题,但是如果我的应用中实际是一个很大的类,那么频繁的复制操作就效率太低下了,而且对我得应用来说,生成一个test对象然后把它加入list中,然后有list来管理其生命周期是很合理的用法!同时我不想每次都要付出复制对象的代价!如果用list<test*>的话又失去了对test对象资源管理的自动化。
大家有什么好的解决方案吗?可以在这里讨论讨论啊!同时希望whyglinux兄台继续发表高见
|
| whyglinux 回复于:2004-04-21 11:16:48
|
以 list 类为基类派生一个新的类,在新类的析构函数中处理内存空间的回收问题。
|
| hh942111 回复于:2004-04-21 12:33:21
|
这个方案我也想到了,并且在一个项目中就是这么做的!但是它还是解决不了智能指针(带引用计数)使用标准模板库的问题,我的想法是在自己实现智能指针时,对于引用计数申明时增加mutable限定符,这样在拷贝时就可以对const SmartPtr&对象改变其引用计数,这样资源管理的自动化和标准模板库的强大特性都可以获得!
不知whyglinux对这个解决方案有何看法?
|
| hh942111 回复于:2004-04-21 12:36:34
|
其实用whyglinux上面提到的重载list<SmartPtr*>,在析构函数中对每个SmartPtr*调用delete的方法也可以,但是又增加了一个适配层,大家发表一下意见,到底哪种方案好呢?
|
| hh942111 回复于:2004-04-21 12:39:52
|
还有用自定义的适配STL的SmartPtr的方案有另一个好处,可以提供==,<运算符的重载以使用map,set等等容器,而用重载list<SmartPtr*>的方案就不够通用了
|
| whyglinux 回复于:2004-04-21 23:46:01
|
带引用计数的智能指针不是C++标准库中的吧。如果你自己实现,我觉得非常困难。增加引用计数非常容易,但是如何减少计数呢?我觉得这是关键,也是难点,你好好考虑考虑。
还有,要正确区分“重载”和“派生”的概念,你在上面有误用。
我说的是以 list 类为基类派生一个新的类,比如叫 pointer_list,专门用来处理元素是指针的情况,在它的析构函数中释放指针指向对象所占用的存储空间。
从你上面的帖子可以看出,你是想用指向 auto_ptr 的指针作为派生类的元素,完全没有这个必要,用普通的指针即可,如 pointer_list< test* >,而不是 pointer_list< auto_ptr* > 或者你的 pointer_list< SmartPtr* >,这时使用它们没有任何的优越性,只能是一种负担。
|
| hh942111 回复于:2004-04-22 01:16:23
|
我的本意是对一个很大的类,比如Test,在与STL结合时希望避免拷贝对象的开销。由于auto_ptr不能配合STL使用,所以考虑效率和使用STL容器,我希望实现自己的智能指针提供这样的功能,这里可以提供实现思路(当然真正的实现还需要考虑更多的东西)
[code:1:b6c6ab58fe]class Smart_ptr
{
private:
// 计数器
// CAtomicCounter对象管理计数值,其AtomicIncrement递增计数值
// AtomicDecrement递减计数值并且在其值为0时返回true
// 在CAtomicCounter内部可以实现多线程的保护
mutable CAtomicCounter* m_pCount;
// 保存的对象指针
Test *m_pData;
public:
Smart_ptr( Test *p )
: m_pData( p )
{
m_pCount = new CAtomicCounter( 1 );
}
Smart_ptr(const Smart_ptr& rhs)
: m_pData(rhs.m_pData)
{
m_pCount->AtomicIncrement();
}
~Smart_ptr()
{
if( m_pCount->AtomicDecrement() )
{
delete m_pCount;
m_pCount = NULL;
delete m_pData;
}
}
}
[/code:1:b6c6ab58fe]
|
| hh942111 回复于:2004-04-22 01:19:25
|
上面的拷贝构造函数漏了东西,应该如下
[code:1:58bfd791e3] Smart_ptr(const Smart_ptr& rhs)
: m_pData(rhs.m_pData),
m_pCount(rhs.m_pCount)
{
m_pCount->AtomicIncrement();
}
[/code:1:58bfd791e3]
|
| dzho002 回复于:2004-04-22 07:15:25
|
这里有一些Smart Pointers的讨论,你可以看看
http://ootips.org/yonat/4dev/
|