中国IT动力,最新最全的IT技术教程
最新100篇 | 推荐100篇 | 专题100篇 | 排行榜 | 搜索 | 在线API文档 | 网通镜像
首 页 | 程序开发 | 操作系统 | 软件应用 | 图形图象 | 网络应用 | 精文荟萃 | 教育认证 | 硬件维护 | 未整理篇 | 站长教程
ASP JS PHP工程 ASP.NET 网站建设 UML J2EESUN .NET VC VB VFP 网络维护 数据库 DB2 SQL2000 Oracle Mysql
服务器 Win2000 Office C DreamWeaver FireWorks Flash PhotoShop 上网宝典 CorelDraw 协议大全 网络安全 微软认证
硬件维护  CPU  主板  硬盘  内存  显卡  显示器  键盘鼠标  声卡音箱  打印机  机箱电源  BIOS  网卡  C#  Java  Delphi  vs.net2005
  当前位置:> 程序开发 > 编程语言 > C/C++
请教一个STL的问题
作者:未知 时间:2005-09-13 19:28 出处:ChinaUnix.net 责编:chinaitpower
              摘要:请教一个STL的问题

刚刚在测试list,auto_ptr的相关使用方法,但是代码编译通不过!请大家帮忙解决。
代码如下
[code:1:bf915ebe56]#include <list>
#include <vector>
#include <memory>
#include <iostream>

using namespace std;

class test
{
public:
        test( int k = 0 )
        {
                i = k;
                cout << "test BBBB - " << i << endl;
        }
        ~test()
        {
                cout << "test DDDD - " << i << endl;
        }
        test( const test& t )
        {
                this->i = t.i;
        }
        const test& operator=( const test& t )
        {
                this->i = t.i;
                return *this;
        }

private:
        int i;
};

typedef auto_ptr<test> test_ptr;
typedef list<test_ptr> test_list;

int main()
{
        test_list tl;

        for( int i = 0; i < 10; i++ )
        {
                test_ptr ptr( new test( i ) );
                tl.push_back( ptr );
        }
}[/code:1:bf915ebe56]
编译提示
[quote:bf915ebe56]/usr/include/g++-3/stl_construct.h: In function `void construct (_T1 *, 
const _T2 &) [with _T1 = test_ptr, _T2 = auto_ptr<test>]':
/usr/include/g++-3/stl_list.h:293:   instantiated from `list<_Tp, _Alloc>::_M_create_node (const _Tp &) [with _Tp = test_ptr, _Alloc = allocator<test_ptr>]'
/usr/include/g++-3/stl_list.h:344:   instantiated from `list<_Tp, _Alloc>::insert (_List_iterator<_Tp, _Tp &, _Tp *>, const _Tp &) [with _Tp = test_ptr, _Alloc = allocator<test_ptr>]'
/usr/include/g++-3/stl_list.h:381:   instantiated from `list<_Tp, _Alloc>::push_back (const _Tp &) [with _Tp = test_ptr, _Alloc = allocator<test_ptr>]'
a.cpp:44:   instantiated from here
/usr/include/g++-3/stl_construct.h:48: passing `const auto_ptr<test>' 
as `this' argument of `auto_ptr<_Tp>::operator 
auto_ptr<_Tp>::auto_ptr_ref<_Tp1> () [with _Tp1 = test, _Tp = test]' 
discards qualifiers
[/quote:bf915ebe56]

 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/

关闭本页
 
首页 | 投资与合作 | 服务条款 | 隐私政策 | 收藏本站 | 设为首页 | 新用户注册 | 免责声明 | 使用帮助
Copyright ©2005-2008 chinaitpower.com All rights reserved. www.chinaitpower.com 版权所有