在cdsn上看了一个帖子,谈到std::string的效率比不上c风格的char。因为std::string使用堆,而c风格的字符串数组在很多情况下可以直接使用栈上的空间,极大的提升了速度。
在效率上,C++能够和C抗衡的一个有力武器就是模板template。我试着写成下面一个同样建立在栈上的c++风格的字符串类,效率应该也不错。下面是我的帖子:
效率高的地方使用std::string当然不好,这个涉及到从heap中动态分配内存,而且在多线程runtime dll中可能还需要mutex保护。如果大小必须在运行时才能决定,c也得同样使用malloc等。
我估计你的意思是应该使用c风格的在栈中构造的字符数组,例如char buf[222]。但是这样的问题就是这个buf必须分配足够的大小,这也是缓冲区溢出经常出现的原因。我们假设这个字符串长度足够,使用char数组仍然有个问题就是就是每次strcat的时侯要进行两次类似strlen的操作,当然intel cpu有专门的指令,例如scasb。
但是如果使用c++风格,你可以自己搞个char数组风格的string(而不使用std::string)就可以避免在进行strcat调用时多次获取字符串的长度。
举个例子:
inline size_t cpp_strcpy( char * dest, const char * src)
{
//copy src to dest and return the copied len
return strlen( strcpy(dest, src)); //垃圾实现,应该使用汇编
}
template<int size>class local_string
{
public:
local_string() : len(0){ sz[0] = 0; }
local_string(const char * str)
{
len = cpp_strcpy(sz, str);
return *this;
}
local_string& operator +=(const char * str)
{
len += cpp_strcpy(sz + len, str); //起始地址直接sz+len,避免再次调用字符串长度。
return *this;
}
local_string& operator=(const char * str)
{
len = cpp_strcpy(sz, str) );
return *this;
}
size_t len() const { return len; }
public: //public算了。
char sz[size];
size_t len;
};
这样以后,在同一个起跑线上(都使用栈上的char×),c++风格的local_string至少不会比c风格的strcat效率低。当然现在我们就需要一个cpp_strcpy,而不是strcpy,该函数不返回一个指针,而是返回拷贝了多长,我上面那个是个垃圾实现,要使用汇编写一个cpp_strcpy的函数应该不难,edi - old_edi就可以实现。
然后使用:
local_string<40> str;
str = "hello";
str += ",";
str += "world";
效率应该比c风格的高,因为它保存了当前字符串的有效长度。特别在需要多次调用+=的场合。
而后我们需要期待C++编译器将local_string的全部的函数内联,甚至无需实例化具体的local_string类,避免代码膨胀。
---------------
汇编不熟悉,cpp_strcpy就懒得写了,反正我现在工程中也用不上。写完以后看汇编应该是c++风格的效率高,毕竟在operator+=的时侯直接使用sz+len就可以马上获得下一个需要拷贝的位置,而且于字符串长度无关,也就无线性关系。测试倒是不好测试,多次循环总感觉不是很专业,好像又涉及到cache命中率的问题。
这个c++风格的有个毛病就是每个local_string的类型都不一致,妨碍了不同长度的local_string实例之间对象的赋值,参数传递等。应该让它们共用一个基类,将len作为第一个成员。