Chinaunix

标题: stl容器中保存string是不是好的做法 [打印本页]

作者: catmonkey_lee    时间: 2008-04-22 21:27
标题: stl容器中保存string是不是好的做法
比如说:  
typedef map<string, string> test_type;

test_type test_obj;
test_obj["test1"]   =  "asdfsfa";


typedef map<char *, char *> test_type;
相比性能如何?


最好就sgi.stl来说,其他实现不太清楚,多谢
作者: converse    时间: 2008-04-22 22:14
先别管性能,后者不一定都是正确的,因为存放的是指针,而不是字符串的内容,很多时候结果会出乎你的意料之外.希望我这么说你能明白我的意思.
作者: catmonkey_lee    时间: 2008-04-22 22:48
当然如果存储指针的话,会提供一个函数对象来实现比较功能,这样应该没有问题吧?
作者: converse    时间: 2008-04-22 22:57
呵呵,你没明白我说的意思.

typedef map<char *, char *> test_type;

test_type t;
t["test"] = "1";

string str = "test";

t.find((char*)str.c_str()) // 这句的结果是不可预料的....
作者: catmonkey_lee    时间: 2008-04-22 23:26
噢,我的意思是这样:
struct ltstr
{
    bool operator()(const char* s1, const char* s2) const
    {
        return strcmp(s1, s2) < 0;
    }
};
typedef map<char *, char *, ltstr> test_type;

这样应该没问题吧?
我试了一下(linux 2.6.20   gcc 4.1.2),不知道其他环境怎样,我好像一直都这么用的,没出问题,望高手明示!!!呵呵,多谢

#include <map>
#include <iostream>
#include <string.h>

using namespace std;

struct ltstr
{
    bool operator()(const char* s1, const char* s2) const
    {
        return strcmp(s1, s2) < 0;
    }
};
typedef map<char *, char *, ltstr> test_type;
int main()
{
test_type t;
t["test"] = "1";

string str = "test";

test_type::iterator iter = t.find((char*)str.c_str());
cout  << iter->first << "  " << iter->second << endl;
}
作者: converse    时间: 2008-04-22 23:26
标题: 回复 #5 catmonkey_lee 的帖子
恩  这样应该可以.
作者: tyc611    时间: 2008-04-22 23:31
优先用前面的吧,就像converse版主所说,在使用string导致性能成为问题时,可以考虑指针形式,但应该用智能指针,且第一个参数应该是const char*指针
作者: catmonkey_lee    时间: 2008-04-22 23:53
我刚开始看stl的源码,有点不太明白的地方:
自己看完后觉得 比如string A 放在容器中的性能应该不会损失太多的(少量数据),因为只是作了一次引用计数加一操作,这样容器中保存string B对象(我假定 string A放入容器后立马被delete,或者A是栈变量),这样的话我觉得应该和智能指针的效果是一样的.

是不是主要因为 string 占用内存空间的问题呢?

多谢 tyc611 的指点: "第一个参数应该是const char*指针"
作者: converse    时间: 2008-04-23 09:36
string比起char*在这个问题中的缺点仅有两个,一个是构造的时候要完全拷贝字符串,一个是string类型的占用空间比char*大,稳定性和正确性肯定是string好.
作者: catmonkey_lee    时间: 2008-04-23 16:32
但是用sizeof来看string对象的话,占用内存为4字节,和char *一样阿?
而且如果string 的拷贝构造实现基础只是引用计数加一的话,那么也不用完全拷贝字符串阿?

所以我还是觉得string可以  几乎   完全替代char *
(当然引用计数加一会涉及锁操作,是会损失效率的)
作者: tyc611    时间: 2008-04-23 18:20
原帖由 catmonkey_lee 于 2008-4-23 16:32 发表
但是用sizeof来看string对象的话,占用内存为4字节,和char *一样阿?
而且如果string 的拷贝构造实现基础只是引用计数加一的话,那么也不用完全拷贝字符串阿?

所以我还是觉得string可以  几乎   完全替代char  ...

各种库的实现方式并不相同,你可以看看Effective STL中Item 15
如果你有兴趣,可以进一步可以看看这篇文章Optimizations That Aren't (In a Multithreaded World)
作者: mars_man    时间: 2008-05-02 03:06
标题: 回复 #1 catmonkey_lee 的帖子
为了避免各种麻烦,容器里建议只用来容纳对象,对象才是自我完整的,自己对自己负责,否则在容器中采用一些原始的类型的话,麻烦会经常光顾的。
作者: yuanchengjun    时间: 2008-05-02 09:45
标题: C++是不完美的,很多事情要自己处理。我不喜欢用模板。请注意这里的hold
class CObject : public virtual IObject
{
private:
    int objref;

protected:
    CObject() :
        objref(0)
    {
    }

public:
    virtual bool equals(const IObject *o) const
    {
        if (this == o)
            return true;

        return false;
    }

    virtual int hold(int refs)
    {
        refs += objref;

        if (refs < 1)
        {
            destroy();
            return refs;
        }

        return objref = refs;
    }

    virtual void destroy()
    {
        delete this;
    }

public:
    virtual ~CObject()
    {
    }
};




class CMap : public CObject, public virtual IMap
{
private:
&nbsp;&nbsp;&nbsp;&nbsp;IArray *array;

public:
&nbsp;&nbsp;&nbsp;&nbsp;virtual void clear()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->clear();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual void add(IObject *o)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPair *p = dynamic_cast<IPair *>(o);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;throw new CException(new CString("add Pair only"));

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->add(o);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual void remove(IObject *o)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->remove(o);
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual int getCount() const
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return array->getCount();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual int getSize() const
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return array->getSize();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual void first()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->first();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual bool hasMore()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return array->hasMore();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual IObject * next()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return array->next();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual void set(IObject *key, IObject *value)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (array->getCount() < 1)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->add(new CPair(key, value));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPair *p;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IObject *k;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int total = array->getSize();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for (int i = 0; i < total; i++)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p = dynamic_cast<IPair *>(array->get(i));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k = p->getKey();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (k->equals(key))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->set(i, new CPair(key, value));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;virtual IObject * get(IObject *key)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IPair *p;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IObject *k;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->first();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while (array->hasMore())
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;p = dynamic_cast<IPair *>(array->next());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;k = p->getKey();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == p)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;continue;

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (k->equals(key))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return p->getValue();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return 0;
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;CMap(IArray *arr)
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array = arr;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (0 == array)
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array = new CArray();
&nbsp;&nbsp;&nbsp;&nbsp;}

&nbsp;&nbsp;&nbsp;&nbsp;~CMap()
&nbsp;&nbsp;&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array->destroy();
&nbsp;&nbsp;&nbsp;&nbsp;}


[ 本帖最后由 yuanchengjun 于 2008-5-2 09:49 编辑 ]
作者: im2web    时间: 2008-05-02 21:48
我的看法是 速度不是最重要的。 正确是第一的。

放string 会慢。 但是放了char * 很可能出错误的结果。 你会怎么选?

先做出正确的, 再做出高效的, 最后是优雅的。 这是我的一贯思想。
作者: wwwsq    时间: 2008-05-03 02:21
原帖由 mars_man 于 2008-5-2 03:06 发表
为了避免各种麻烦,容器里建议只用来容纳对象,对象才是自我完整的,自己对自己负责,否则在容器中采用一些原始的类型的话,麻烦会经常光顾的。



我们的做法恰好相反,我们从不在容器里面放对象。我们只在容器里面放整数和指针。

首先,容器不适合放自定义对象(因为拷贝构造之类的麻烦事)。
其次,容器在放string之类的对象的话,90%的程序员会搞不清楚内存问题。

所以,我们从不偷懒,容器里面我们只存放基本数据类型。
作者: im2web    时间: 2008-05-03 12:59
我们的做法恰好相反,我们从不在容器里面放对象。我们只在容器里面放整数和指针。


多线程中间,当你需要删除掉容器里面的这个对象, 你需要保证没有线程正在使用这个对象。
这个是非常困难的,一件事情。首先,你需要锁定这个容器, 然后 你需要保证,没有人在使用这个对象。 一点点问题 就可能造成,你删除了一个 别的线程正在使用的一个对象。
作者: wwwsq    时间: 2008-05-03 13:28
标题: 回复 #16 im2web 的帖子
"多线程中间,当你需要删除掉容器里面的这个对象, 你需要保证没有线程正在使用这个对象"

首先,会出现这种情况,说明这个程序的架构设计有问题。
其次,真有这种情况,也可以用删除队列来解决(我们维护老程序的时候遇到过这样的问题)。
第三,在容器里面放对象,完全不能解决对象的跨线程安全问题。除了string这样少数的独特的对象,大多数对象仍然需要你自己维护线程安全性。
第四,不能因噎废食,为了配合不好的设计而放弃良好的设计。

[ 本帖最后由 wwwsq 于 2008-5-3 13:32 编辑 ]
作者: im2web    时间: 2008-05-03 19:22
原帖由 wwwsq 于 2008-5-3 13:28 发表
"多线程中间,当你需要删除掉容器里面的这个对象, 你需要保证没有线程正在使用这个对象"

首先,会出现这种情况,说明这个程序的架构设计有问题。
其次,真有这种情况,也可以用删除队列来解决(我们维护老 ...


很多时候不合理的设计是因为现实环境的要求。删除队列也不能完全解决这个问题。 需要用引用数记录 + 小范围锁定的问题来解决。
非常繁琐。 但是其实这样做可以非常高的提高多线程的效率。  简单的算法 很简单也是正确的。但那是单线程。如果是多线程,很多设计反而会非常的古怪,而繁琐。 但是这的确是高效的。




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2