关于C++ string类的写时复制

问题代码:

 //将strGrammar的第(pos+1)个字符向后移动一位 
void BackMovePoint(string& strGrammar, int pos)
{

     char* grammar  = const_cast(strGrammar.c_str());//  正确的写法: string grammar = (char*)(strGrammar.c_str());

    char temp = grammar[pos];
    grammar[pos] = grammar[pos + 1];
    grammar[pos + 1] = temp;
    strGrammar = "";
    int nLength = strlen(grammar); // grammar.length(); 
    for (int i = 0; i < nLength; i++)
        strGrammar += grammar[i];
}

 

在另一个函数中调用此函数:

for (int m = 0; m < vecSameEntrance.size(); m++)  //vecSameEntranc类型:vector
   {
     log <<"m: "<

       string tempStr=vecSameEntrance[m];

       int pointIndex = tempStr.find('.',0);
   

       if (pointIndex < tempStr.length() - 1)
       {
           BackMovePoint(tempStr, pointIndex);

           pointIndex = tempStr.find('.', 0);
           if (pointIndex == tempStr.length() - 1)
               bNodeEnd = true;
   
           ProduceCLOSUE(newvecGrammar, tempStr, vecGrammar);
      log <<"after: "<<"m: "<

     }

}

 

日志输出:

m: 0 S->.E 493
after: m: 0 S->E. 508
m: 1 E->.E+E 493
after: m: 1 E->E.+E 508
m: 2 E->.E*E 493
after: m: 2 E->E.*E 508

 

vecSameEntrance中的值本不应改变的,但在调用BackMovePoint之后全都改变了!由于程序其他地方还使用到此变量,由于变量的改变导致程序崩溃。调了一个下午才找到原因:string类的写时复制!tempStr与vecSameEntranc中的string值其实是共享同一块内存,指向的是同一个内存地址,在BackMovePoint将tempStr强制转换const_cast成char*,并进行改写,导致vecSameEntrance对应的string的值也被修改。

 

关于string类的写时复制:

string类内存:string类中必有一个私有成员,其是一个char*,用户记录从堆上分配内存的地址,其在构造时分配内存,在析构时释放内存。因为是从堆上分配内存,所以string类在维护这块内存上是格外小心的,string类在返回这块内存地址时,只返回const char*,也就是只读的,如果你要写,你只能通过string提供的方法进行数据的改写。

 

详见:标准C++类std::string的内存共享和Copy-On-Write技术,作者:陈皓http://blog.163.com/digoal@126/blog/static/163877040201011318659953/

作者分析的相当精彩,C++是一把双刃剑,只有了解了原理,你才能更好的使用C++。否则,必将引火烧身。如果你在设计和使用类库时有一种“玩C++就像玩火,必须千万小心”的感觉。

 

你可能感兴趣的:(C++)