其实我想只要能看到这篇博客的朋友,又是学过C/C++的都应该知道,如果一个对象需要作为函数调用的一个参数,同时对象分配的内存又非常大的时候,应该使用const T&来作为参数。

虽然知道这一点,但是我还是经常会在传递string参数的时候,直接不使用引用,今天仔细看了一下string的写时copy,突然想到,大家看到string就要求传递引用会不会只是一种惯性驱使呢,string的copy真的会把分配的内存全部copy一遍?

我们其实做一个简单的实验就知道了,代码如下:

#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
void test1(string c)
{
    printf("c[%u]\n",c.c_str());
}
void test2(const string& d)
{
    printf("d[%u]\n",d.c_str());
}
void test3(const string e)
{
    printf("e[%u]\n",e.c_str());
}
int main(int argc, const char *argv[])
{
    string a = "one";
    string b = a;
    printf("a[%u]b[%u]\n",a.c_str(),b.c_str());
    test1(a);
    test2(a);
    test3(a);
    a="s";
    printf("a[%u]b[%u]\n",a.c_str(),b.c_str());
    return 0;
}

输出结果:

a[4009044]b[4009044]
c[4009044]
d[4009044]
e[4009044]
a[4009068]b[4009044]

答案应该很明确了,有些语言规范所恪守的string必须传递引用其实是有些教条主义了。

其实不只是string,只要将自己实现的类的copy构造函数增加计数器判断,也可以达到一样的效果。

============================我是华丽的分割线===============================
对string其实还有一种用法,即不作为字符串而作为buf管理器来用(突然觉得很像python的str类型,并不是以\0来决定结尾)
如下用法

#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
int main(int argc, const char *argv[])
{
    string a = "s";
    printf("aptr[%u]\n",a.c_str());
    printf("a[%s][%u]\n",a.c_str(),a.size());
    a.resize(10);
    printf("aptr[%u]\n",a.c_str());
    printf("a[%s][%u]\n",a.c_str(),a.size());
    for (int i = 0; i < a.size(); i++) {
        printf("%02x ",a[i]);
    }
    memset((char*)a.c_str(),0,a.size());
    printf("\n");
    for (int i = 0; i < a.size(); i++) {
        printf("%02x ",a[i]);
    }
    printf("\n");
    printf("a[%s][%u]\n",a.c_str(),a.size()); 
    string b = a;
    printf("aptr[%u]bptr[%u]\n",a.c_str(),b.c_str());
    printf("b[%s][%u]\n",b.c_str(),b.size());
    return 0;
}

输出结果:

aptr[4009044]
a[s][1]
aptr[4009068]
a[s][10]
73 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 
a[][10]
aptr[4009068]bptr[4009100]
b[][10]

从上面的结果,我们可以得到如下几个信息:
1.string在resize的时候,会重新申请新的内存,并将原来的内存copy到新内存上。
2.copy构造函数中也不是以\0为拷贝的结束符,而是将整个size()都进行copy。
3.直接使用resize破坏了string内部的计数,所以在string b = a的时候,b重新分配了一块全新的内存而不是和a共用。
由上面3点可以看出,string完全可以用来做一个简单的buf管理器,不过一旦决定将string用作buf就不要在使用字符串的方法,如==来判断两端buf是否相等之类,否则会有很多奇怪的错误。不过如果担心b和a不小心公用同一块内存的话,可以使用resize方法来为b自己copy出一份内存出来。

OK,目前关于string的理解就这么多,如果有不对之处还请多多指教。

一个简单的stl中string的split函数

在python,c#等语言中,string都是默认提供split这个函数的,C++里面却没有默认实现,但又经常会用到,所以就简单实现了一个: C++ ...

阅读全文

关于在“写时拷贝”发生的情况下直接操作string中内容出现的问题

注:本文是公司同事的一个分享,由于很有代表性,特分享在此,希望对大家有用。 上次welkin在处理一个豆瓣的cgi时遇到1个奇怪的问题,就是对一个string对象的...

阅读全文

string转化大小写(C++)

如何将一个字符串转换成大写或者小写?这是字符串匹配中经常需要做的事情,然而C++的Standard Library并没有提供将std::string转成大写和小写的功能,只有在...

阅读全文

3则回应给“关于在函数调用时传递string引用的必要性”

  1. alexandercer说道:

    感觉用着怪怪的…如果用string做buf的话,岂不是回到用string.h做memset..名称和功能不对应…有点怪怪的感觉…

    [回复]

    Dante 回复:

    恩,其实我也觉得不是很舒服,不过也只能先这样用来满足简单的buf管理要求~~~

    [回复]

  2. 小保哥说道:

    Copy on Write.

    [回复]

发表评论