【C++】的浅copy,深copy,写时copy和引用计数的copy 面试汇总

1. 分析C语言中字符串的缺陷
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP(面向对象)的思想,而且底层空间需要用户自己管理,稍不留神可
能还会越界访问。

  1. 熟悉string类的常见接口并熟练应用,完成在线OJ题目
    翻转字符串I
class Solution {
public:
 string reverseString(string s) {
 if(s.empty())
 	return s;
 
 size_t start = 0;
 size_t end = s.size()-1;
 
 while(start < end)
 {
 	swap(s[start], s[end]);
 	++start;
 	--end;
 }
 
 	return s;
 }
};

找字符串中第一个只出现一次的字符

class Solution {
public:
 int firstUniqChar(string s) {
 
 // 统计每个字符出现的次数
 int count[256] = {0};
 int size = s.size();
 for(int i = 0; i < size; ++i)
	 count[s[i]] += 1;
 
 // 按照字符次序从前往后找只出现一次的字符
 for(int i = 0; i < size; ++i)
 	if(1 == count[s[i]])
 	return i;
 
 return -1;
 }
};

3. 熟悉什么是浅拷贝?浅拷贝会存在什么危害 ?
浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来。如果对象中管理资源,最后就会导致多个对象共享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为有效,所以当继续对资源进行操作时,就会发生访问违规。
4. 浅拷贝解决方法一:深拷贝

深拷贝:给每个对象独立分配资源,保证对多个对象之间不会因共享资源而造成多次释放,造成程序崩溃问题。
深拷贝代码实现

class string {
	string(const char*str = "")
	{
		if(str == nullptr)
		{
			str = "";
		}
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}
	string(const string& s):_str = nullptr
	{
		string strTmp(s._str);
		swap(_str,strTmp);
	}
}

5. 浅拷贝解决方式二:写时拷贝(熟悉写时拷贝原理,为什么要引入引用计数,引用计数为什么要设置成指针方式,),并分析写时拷贝的缺点
写是拷贝就是编程界“懒惰行为”——拖延战术的产物。举个例子昨天晚上你吃完晚饭但是不想洗碗,到第二天中午再次吃饭时才去洗昨天晚上的碗。这就是一种非常典型的“懒惰行为”。

要实现写时才拷贝,需要解决两个问题,一个是内存共享(俩个指针同时可以读取到同一内存上的数据),一个是Copy-On-Wirte(当要对数据进行写时重新开辟内存,在新开辟的内存上对数据进行修改)。

1、 Copy-On-Write的原理是什么?
Copy-On-Write一定使用了“引用计数”,是的,必然有一个变量类似于RefCnt。当第一个类构造时,string的构造函数会根据传入的参数从堆上分配内存,当有其它类需要这块内存时,这个计数为自动累加,当有类析构时,这个计数会减一,直到最后一个类析构时,此时的RefCnt为1或是0,此时,程序才会真正的Free这块从堆上分配的内存。

引用计数就是string类中写时才拷贝的原理!

2、 string类在什么情况下才共享内存的?

1)以别的类构造自己,2)以别的类赋值。第一种情况时会触发拷贝构造函数,第二种情况会触发赋值操作符。这两种情况我们都可以在类中实现其对应的方法。对于第一种情况,只需要在string类的拷贝构造函数中做点处理,让其引用计数累加;同样,对于第二种情况,只需要重载string类的赋值操作符,同样在其中加上一点处理。

3、 string类在什么情况下触发写时才拷贝(Copy-On-Write)?
当然是在共享同一块内存的类发生内容改变时,才会发生Copy-On-Write。比如string类的[]、=、+=、+、操作符赋值,还有一些string类中诸如insert、replace、append等成员函数,包括类的析构时。

修改数据会触发Copy-On-Write。

4、 Copy-On-Write时,发生了什么?

If  ( RefCnt>0 ) {
    char* tmp =  (char*) malloc(strlen(_Ptr)+1);
    strcpy(tmp, _Ptr);
    _Ptr = tmp;
}

通过代码我们可以知道 ,Copy-On-Write时通过对“计数”的判断,然后开辟空间,最后将_Ptr的内容拷贝给tmp并将内存交换。
5、Copy-On-Write的缺点内存泄漏

int main(void) {
    string the_base(1024 * 1024 * 10, 'x');
    fprintf(stdout,"the_base's first char is [%c]\n",the_base[0] );
    long begin =  getcurrenttick();
    for (int i = 0; i < 100; i++) {
        string the_copy = the_base;
    }
    fprintf(stdout,"耗时[%d] \n",getcurrenttick() - begin );
}

C++标准认为,当你通过迭代器或[]获取到string的内部地址的时候,string并不知道你将是要读还是要写。这是它无法确定,如果你要写而它认为读,那没就会是浅拷贝,很可能导致内存泄漏。为此,当你获取到内部引用后,为了避免不能捕获你的写操作,它在此时废止了写时才拷贝技术!

发布了28 篇原创文章 · 获赞 70 · 访问量 1892

猜你喜欢

转载自blog.csdn.net/famur/article/details/105003704
今日推荐