說在開始
作者:憨豆酒(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過來的就行。