13.1,拷貝、賦值與銷燬
13.1.1拷貝構造函數
直接初始化與拷貝初始化的區別:直接初始化使用函數匹配,拷貝初始化是將右側對象拷貝到正在創建的對象中
A(const A&)
EX1:
1,拷貝構造函數的定義:
一個構造函數的第一個參數是自身類型的引用,且任何額外參數都有默認值。
2,出現場合:
- 用“=”定義變量,
- 將一個對象作爲實參傳遞給一個非引用類型的形參,
- 從一個返回類型爲非引用類型的函數返回一個對象,
- 花括號{} 初始化
EX2 :
拷貝構造函數自己的參數必須是引用類型。
因爲如果不是的話,在調用拷貝構造函數時,將一個對象作爲實參傳遞給一個非引用類型的形參時,會再次調用該拷貝構造函數陷入死循環。
EX5
HasPtr(const string &Hp){
//*ps = *Hp.ps; 會執行出錯
ps = new string(*Hp.ps)
i = Hp.i;
}
13.1.2,拷貝賦值運算符
一般拷貝賦值運算符組合了析構函數和構造函數的工作:好的使用方法是:先將右側運算對象特殊成員(如指針)保存到局部臨時變量中,然後銷燬左側運算對象的需要顯示銷燬的成員(如指針)(爲了防止自賦值,先後順序不能變),再將臨時對象賦值。(參考ex22)
A& operator=(const A&)
EX6
作用:控制對象的賦值.。注意:返回值爲左側運算對象的引用。
EX7 ???
EX8
13.1.3 析構函數
指向一個對象的指針或引用離開作用域時,析構函數不會執行
EX9
作用:釋放對象使用的資源,並銷燬對象的非static數據成員
EX10 ???
EX11
~HasPtr(){
delete ps;
}
EX13
#include <iostream>
#include <vector>
#include <initializer_list>
struct X {
X() { std::cout << "X()" << std::endl; }
X(const X&) { std::cout << "X(const X&)" << std::endl; }
X& operator=(const X&) { std::cout << "X& operator=(const X&)" << std::endl; return *this; }
~X() { std::cout << "~X()" << std::endl; }
};
void f(const X &rx, X x)//構
{
std::vector<X> vec;
vec.reserve(2);
vec.push_back(rx);//構
vec.push_back(x);//構
}
int main()
{
X *px = new X;//構
f(*px, *px);
delete px;
return 0;
}
順序:構構析構構析析析 –》 構構構構析析析析
13.1.4,三/五法則
需要析構函數則也需要拷貝和賦值函數。需要拷貝函數則需要構造函數,反之亦然。
13.1.6,阻止拷貝
??? iostream類阻止拷貝
???P451 第三段
EX18,19
Employee{
private:
string name;
int id;
static int flag;
public:
Employee(){id = ++flag;}
Employee(string str):name(str){id = ++flag;}
Employee(const Employee& e)= delete;
Emplyee& operator=(const Employee& e)=delete;
}
int Employee::flag = 0;
在現實生活中拷貝或者賦值員工的個人信息沒有實際意義。
EX20,21 ???
13.2拷貝控制和資源管理
13.2.1,行爲像值的類
ex22
class HasPtr {
private:
string *ps;
int i;
public:
HasPtr(const string& str){ps = new string(str);}
HasPtr(const HasPtr& hp){
ps = new string(*p.ps);
i = hp.i;
}
HasPre& operator=(const HasPtr& hp){
auto tem = new string(*p.ps);
delete ps;//這是拷貝賦值運算,原來的地址空間需要回收
ps = tem;
i = hp.i;
return *this;
}
~HasPtr(){delete ps;}
}
ex25,26 ???
13.2.2行爲像指針的類
class HasPtr {
private:
string *ps;
int i;
size_t *use;
public:
HasPtr(const string& str):ps(new string(str)),i(0),use(new size_t(1)){}
HasPtr(const HasPtr& hp):ps(hp.ps),i(hp.i),use(hp.use){++*use;}
HasPre& operator=(const HasPtr& hp){
++*hp.use;//右側運算對象的空間引用計數器加1
if(--(*use)==0){
delete ps;
delete use
}//如果無指針指向左側運算對象,則釋放空間
ps = hp.ps;
i = hp.i;
use = hp.use;
return *this;
}
~HasPtr(){
if(--*use==0){
delete ps;
delete use;
}
}
}
13.28 ???
13.32
#include <string>
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
class HasPtr
{
public:
friend void swap(HasPtr&, HasPtr&);
friend bool operator<(const HasPtr &lhs, const HasPtr &rhs);
HasPtr(const std::string &s = std::string(),int num=0)
: ps(new std::string(s)), i(num)
{ }
HasPtr(const HasPtr &hp)
: ps(new std::string(*hp.ps)), i(hp.i)
{ }
HasPtr& operator=(HasPtr tmp)
{
this->swap(tmp);
return *this;
}
void display() {
cout << i << *ps << endl;
}
~HasPtr()
{
delete ps;
}
void swap(HasPtr &rhs)
{
using std::swap;
swap(ps, rhs.ps);
swap(i, rhs.i);
std::cout << "call swap(HasPtr &rhs)" << std::endl;
}
void show() const
{
std::cout << *ps << std::endl;
}
private:
std::string *ps;
int i;
};
void swap(HasPtr& lhs, HasPtr& rhs)
{
lhs.swap(rhs);
}
bool operator<(const HasPtr &lhs, const HasPtr &rhs)
{
return *lhs.ps < *rhs.ps;
}
int main() {
vector<HasPtr> vec_hp;
HasPtr hp1("hi", 1);
HasPtr hp2("ab", 2);
HasPtr hp3("cd", 3);
vec_hp.push_back(hp1);
vec_hp.push_back(hp2);
vec_hp.push_back(hp3);
sort(vec_hp.begin(),vec_hp.end());
for (auto i : vec_hp) {
i.display();
}
}