【高質量C++/C總結12】拷貝函數C++標準庫複數類string解析

說在開始

作者:憨豆酒(YinDou),聯繫我[email protected],熟悉圖形學,圖像處理領域,本章的源代碼可在此倉庫中找到: https://github.com/douysu/person-summary 如果大家發現錯誤以及不合理之處,還希望多多指出。

我提煉了《C++ Primer》、《侯捷C++》、《高質量程序設計指南——C/C++語言》等資料中的重要部分,並總結成此博文。其中涉及到許多我個人對C++的理解,如若有不合理之處,還請朋友們多多指出,我會虛心接受每一個建議。

觀看了侯捷老師有關於拷貝構造和拷貝賦值的方法,其中涉及到淺拷貝,深拷貝等問題,當然在看本節部分的時候可能會產生很多的問題,我也是如此,產生問題的原因是因爲對C/C++的內存管理機制掌握不好,當掌握了C/C++內存管理的機制後這些問題就會迎刃而解了。我也會寫一篇關於C/C++內存管理機制的博客的。在這裏進行總結。

本節解析了C++標準庫當中的string類,自己用代碼實現了,當然這裏是閹割版,因爲C++標準庫當中的string功能實在是太複雜了,這裏實現了幾個簡單的string的構造函數,拷貝函數等。

我們應當時刻注意一點:當我們設計的類當中有指針的時候,一定要時刻注意內存泄露,野內存等問題,也就是當類中有指針的時候,我們應該時刻注意。
如果自己的類當中含有指針,不可以使用編譯器默認的拷貝函數,接下來我將會解釋爲什麼不可以使用默認器的拷貝函數。

代碼部分

先給出代碼,看一下整個string類的基本架構吧,然後纔好理解下面的概念問題,同樣,侯捷老師把函數的實現代碼放到了頭文件當中,當然他使用了inline,大家需要注意.h文件用來聲明是不進行編譯的。
String.h

#ifndef _MY_STRING
#define _MY_STRING
class String
{
public:
	String(const char * cstr=0);//滿足 String s1("hellow")的構造方式
	String(const String& str);//滿足 String s1(s2)的構造方式
	String& operator = (const String& str);//滿足 s1=s2的方式 
	~String();
private:
	char * m_data;//自己的數據數組
};
#include <cstring>
inline String::String(const char * cstr)//構造函數,滿足 String s1("hellow")的構造方式
{
	if (cstr) {//判斷是不是0
		m_data = new char[strlen(cstr) + 1];
		strcpy(m_data, cstr);
	}else {
		m_data = new char[1];
		*m_data = '\0';
	}
}
inline String::String(const String& str)//構造函數,滿足 String s1(s2)的構造方式
{
	m_data = new char[strlen(str.m_data) + 1];
	strcpy(m_data, str.m_data);
}
inline String::~String()//析構函數
{
	delete[]  m_data;
}
inline String& String::operator =(const String& str){
	if(this==&str){//檢測自我賦值 
		return *this;
	}
	delete[] m_data;
	m_data = new char[ strlen(str.m_data) + 1 ];
   	strcpy(m_data, str.m_data);
   	return *this;
}
#endif //_MY_STRING

main.cpp

#include <iostream>
#include "String.h"
using namespace std;
int main() {
	String s1("hello"); //第一種構造方式
    String s2("world"); 
    String s3(s2);//第二種構造方式
	/*
		兩種構造方式:
		1、此時的s1是不存在的,直接將hello給s1
		2、第二種方式,s2和s3都是存在的,將s2的內容傳遞給s3
	*/
    s3 = s1;//把s1的值拷貝給s3,這裏重載了操作符“=”,所以纔可以完成,否則出現淺拷貝問題,稍後解釋,繼續往下看。
	cin.get();
	return 0;
}

幾個概念

淺拷貝

如果自己使用系統的拷貝函數。也就是直接賦值=。會出現以下的錯誤結果:淺拷貝

從圖中可以看到有兩個String 對象 a和b ,其中a當中的data指針指向的是“Hello”,b的data指針指向的是“Wordld”。當使用系統的a=b時,會出現圖片下半部分的錯誤。也就是a和b兩個對象中的指針會同時指向“Hello”

這樣會帶來兩個問題:

1、造成內存泄露,兩個data指針同時指向一個區域,“world”區域沒有進行釋放。
2、a,b兩個對象中的data指針同時指向一個區域,操作可能會出現錯誤。

深拷貝

這裏使用了C原來的拷貝函數,首先動態分配了一塊內存,然後將另一個字符串中的內容拷貝到新分配的內存中 。我使用VS2015使用這段代碼的時候會提示該方法可能會出現安全性錯誤,建議使用strcpy_s,但是使用C-Free這種輕量行的編譯器就不會出現這種錯誤。我的猜想有以下兩點
1、C-Free比較輕量,VS適用於大型項目的開發,比較嚴謹。
2、C-Free更加傾向於C語言,對於C++語言的完善的可能不是很好。

拷貝賦值函數

可以看出,此塊代碼是重載了操作符“=”也就是s1=s2所做的事情,這個方法也是比較重要的方法。其大致可以分爲兩大部分。
1、首先釋放this指針指向的內容,然後分配一塊與str指向的大小相同的內存區域,然後在進行深拷貝。
2、其中還有檢測自我賦值的內容,這裏應該時刻注意。如果檢測到是自己賦值給自己,那麼什麼都不要做,直接返回,效率更高
3、如果不寫自我檢測可能會出現的錯誤結果:

去掉自我檢測部分的代碼,一步步分析:
前提,兩個指針都是指向的Hello,當執行第一句代碼delete[] m_data;後,兩個指針指向的都是空內容,此時m_data = new char[ strlen(str.m_data) + 1 ];就無法處理。應該時刻注意。

最後

如果覺得文字內容不好理解的話,大家可以想看視頻資源的話,可以 VX qq619192323。有什麼錯誤還希望大家指出,一起共同進步。
如果您喜歡C++,喜歡3D,並且想了解一點深度學習的知識,加入我們的QQ羣,羣裏面全都是年輕的開發者,歡迎大家的加入討論。就說是CSDN過來的就行。
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章