C++ 之 stl::string 写时拷贝导致的问题
一、写时拷贝原理
String是使用计数器来记录引用计数,当有新的string对象共享内存块时,计数器+1,当有对象触发写时拷贝或析构时,计数器-1。
那么计数器存放在哪里呢?std::string会在堆里分配空间存储计数器,由第一个创建的对象分配并初始化计数器。stl的实现就是在string内存空间的最前面分配了空间存储计数器。
二、写时拷贝容易引发的问题
问题主要出现在直接使用 sprintf 操作 string 的内部指针地址 (char)s.c_str() 。
#include <stdio.h>
#include <iostream>
#include <string>
int main()
{
std::string s1 = "efghijk";
std::string s2 = s1;
std::string s3 = s1;
sprintf((char*)s1.c_str(), "%s", "abcde");
std::cout << "s1=" << s1 << std::endl;
std::cout << "s2=" << s2 << std::endl;
std::cout << "s3=" << s3 << std::endl;
}
输出结果为(j没有显示在string是由于在sprintf时,abcde后面还有一个\0字符):
s1=abcdek
s2=abcdek
s3=abcdek
通过 string::resize() 分配内存空间。 通过 string::c_str() 直接获取内存空间的起始地址并写入数据。
这样会导致s1和s2和s3都发生变化,所以尽量不要使用string的.c_str函数进行赋值操作,不然容易由于copy on right导致的无法直观想到的错误。