纯原创 转载请注明出处:http://blog.csdn.net/axuan_k
13.2 13.3 13.4 13.5
#include
using namespace std;
class Point{
int a;
};
Point global; //13.4
Point foo_bar(Point arg) //1
{
Point local = arg, *heap = new Point(global); //2,3
*heap = local;
Point pa[ 4 ] = { local, *heap }; //4,5
return *heap; //6
}
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){} // 13.5
private:
string *ps;
int i;
};
int main(){
// 13.2
// 拷贝构造函数的参数如果是实参,那就需要在调用它的时候复制 原对象给它,
// 而这个复制过程又需要调用拷贝构造函数才能完成,如此无限循环
// 13.3
// StrBlob中智能share指针指向的对象的use_count会+1
// 而StrBlobPtr中智能weak指针指向的use_count不会变
// 是share指针和weak指针的性质决定的
return 0;
}
#include
using namespace std;
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){}
HasPtr& operator=(const HasPtr& hp){ //13.8
ps=new string(*hp.ps);
i=hp.i;
return *this;
}
private:
string *ps;
int i;
};
int main(){
// 13.6
// 拷贝赋值运算符: operator=
// 当需要进行同类中对象的赋值时使用它
// 完成 将右侧所有非static的成员赋予左侧运算对象的对应成员
// 当用户未定义自己的拷贝赋值运算符时
// 13.7
// StrBlob赋值时 被赋值的StrBlob指向容器的use_count-1,赋值一方StrBlob指向容器的use_count+1
// StrBlobPtr的两侧指向容器的use_count都不会变
return 0;
}
13.9 13.10 13.11 13.12 13.13
#include
#include
using namespace std;
class HasPtr{
public:
HasPtr(const string&s=string()):ps(new string(s)),i(0){}
HasPtr(const HasPtr& hp):ps(new string(*hp.ps)),i(hp.i){}
HasPtr& operator=(const HasPtr& hp){
ps=new string(*hp.ps);
i=hp.i;
return *this;
}
~HasPtr(){delete ps;} //13.11
private:
string *ps;
int i;
};
struct X{
X(){cout<<"X()"<vec;
cout<<"1111111111"<
13.14 13.15 13.16 13.17
#include
#include
using namespace std;
class numbered{
public:
numbered():mysn(get_id()){}
numbered(const numbered& x):mysn(get_id()){}
int get_id(){return ++num;}
int mysn;
static int num;
};
int numbered::num=0;
void f(const numbered& x){cout<
13.18 13.19 13.20
#include
#include
using namespace std;
class Employee{ //13.18
public:
Employee()=default;
Employee(const string& s):name(s),id(get_id()){}
Employee(const Employee& e)=delete;
Employee& operator=(const Employee& e)=delete;
private:
string name;
int id;
static int num;
const int get_id()const{return ++num;}
};
int Employee::num=0;
int main(){
// 13.19
// 需要 因为每个对象都应该有一个独立的id
// 默认合成的拷贝构造函数和拷贝赋值函数都会复制id,不应该有拷贝和赋值的操作
// 13.20
// TextQuery和QueryResult所有成员(包括智能指针和容器)都将被拷贝
return 0;
}
13.21
#ifndef MY_CLASS
#define MY_CLASS
#include
#include
#include
#include
13.24 13.25 13.26
#include
#include
#include
#include
#include
using namespace std;
class StrBlob
{
public:
typedef vector::size_type size_type;
StrBlob():data(make_shared>()){}
StrBlob(initializer_listil):data(make_shared>(il)){}
StrBlob(const StrBlob& sb):data(make_shared>(*sb.data)){} //13.26
StrBlob& operator=(const StrBlob& sb){ //13.26
data=make_shared>(*sb.data); //拷贝赋值函数不需要定义局部临时变量 shared_ptr特性
return *this;
}
size_type size()const{return data->size();}
bool empty(){return data->empty();}
void push_back(const string& str){data->push_back(str);}
void pop_back(){
check(0,"pop_back on empty StrBlob");
data->pop_back();
}
string& front()const
{
check(0,"front on empty StrBlob");
return data->front();
}
string& back()const
{
check(0,"back on empty StrBlob");
return data->back();
}
private:
shared_ptr> data;
void check(size_type i,const string& msg)const{
if(i>=data->size())
throw out_of_range(msg);
}
};
int main(){
// 13.24
// HasPtr的成员ps指向的string的内存是动态分配的,如果用合成的析构函数,那么那段内存就不会被释放,造成内存泄露
// 13.25
// 我们想让StrBlob像一个值,那么每个StrBlob都应该有一块独立的内存,
// 而合成版本的拷贝构造函数和拷贝赋值运算符不会分配内存,需要我们自己定义函数来分配内存
// 又因为StrBlob的唯一成员是智能指针,当指针指向对象的use_count为1时自动销毁内存,所有不需要我们来手动销毁动态内存.
return 0;
}
13.27 13.28
#include
#include
using namespace std;
class HasPtr{ //13.27
public:
HasPtr():ps(new string()),use(new int(1)){}
HasPtr(const string&s=string()):ps(new string(s)),i(0),use(new int(1)){}
HasPtr(const HasPtr& hp):ps(hp.ps),i(hp.i),use(hp.use){
++(*hp.use);
}
HasPtr& operator=(const HasPtr& hp){
++(*(this->use));
--(*(this->use));
if(this->use==0){
delete (this->ps);
delete (this->use);
}
this->ps=hp.ps;
this->i=hp.i;
this->use=hp.use;
return *this;
}
~HasPtr(){
--(*(this->use));
if(this->use==0){
delete (this->ps);
delete (this->use);
}
}
private:
string *ps;
int i;
int* use;
};
class TreeNode{ //行为像指针 //13.28
public:
TreeNode():value(""),count(new int(1)),left(nullptr),right(nullptr){} //left,right指向的内存应该在其他函数内分配
TreeNode(const TreeNode& tr)
:value(tr.value),count(tr.count),left(tr.left),right(tr.right){
++(*tr.count);
}
TreeNode& operator=(const TreeNode& tr){
++(*tr.count);
--(*this->count);
if(*(this->count)==0){
delete this->count;
delete this->left; //可以delete空指针
delete this->right;
}
this->value=tr.value;
this->count=tr.count;
this->left=tr.left;
this->right=tr.right;
return *this;
}
~TreeNode(){
--(*this->count);
if(*(this->count)==0){
delete this->count;
delete this->left;
delete this->right;
}
}
private:
string value;
int* count;
TreeNode *left;
TreeNode *right;
};
class BinStrTree{ //行为像值
public:
BinStrTree():root(new TreeNode()){}
BinStrTree(const BinStrTree& bst):root(new TreeNode(*bst.root)){}
BinStrTree& operator=(const BinStrTree& bst){
TreeNode* tr=new TreeNode(*bst.root);
delete this->root;
this->root=tr;
return *this;
}
~BinStrTree(){
delete this->root;
}
private:
TreeNode *root;
};
int main(){
BinStrTree bst,bst2;
bst2=bst;
BinStrTree bst3=bst;
return 0;
}
11.29 11.30 11.31 11.32
#include
#include
#include
#include
using namespace std;
class HasPtr{
friend void swap(HasPtr& lhs,HasPtr& rhs){
// 11.29
// 该swap内部调用的并不是自己,而是std::swap
// 同时这些swap的参数类型也各不相同,证明不是递归调用自己
cout<<"call swap(HasPtr&,HasPtr&)"<ps;
ps=newp;
i=hp.i;
return *this;
}
~HasPtr(){delete ps;}
//private:
string *ps;
int i;
};
int main(){
// 11.30
HasPtr a("aaaaaaa");
HasPtr c("sssssss");
swap(a,c);
// 11.31
vectorvec{c,a};
vec.push_back(HasPtr("gggggggggg"));
vec.push_back(HasPtr("wwwwwwwwww"));
vec.push_back(HasPtr("dddddddddd"));
sort(vec.begin(),vec.end());
// 11.32
// 本质上值版本的swap就是为了避免临时的内存分配,从而提高性能
// 而指针版本的类在赋值的过程中本来就不需要分配临时内存,所以指针版本不会得到益处.
return 0;
}
13.33-----13.38
//Folder_and_Message.h
#include
#include
class Folder;
//13.34
class Message {
friend class Folder;
public:
explicit Message(const std::string &str = ""):contents(str) { }
Message(const Message&);
Message& operator=(const Message&);
~Message();
void save(Folder&);
void remove(Folder&);
private:
std::string contents;
std::set folders;
void add_to_Folders(const Message&);
void remove_from_Folders();
// 13.37
void addFldr(Folder *f) { folders.insert(f); }
void remFldr(Folder *f) { folders.erase(f); }
};
// 13.36
class Folder {
friend class Message;
public:
Folder(){};
Folder(const Folder &);
Folder& operator=(const Folder &);
~Folder();
private:
std::set msgs;
void add_to_Message(const Folder&);
void remove_from_Message();
void addMsg(Message *m) { msgs.insert(m); }
void remMsg(Message *m) { msgs.erase(m); }
};
//Folder_and_Message.cpp
#include"Folder.h"
using namespace std;
Message::Message(const Message& msg)
:contents(msg.contents),folders(msg.folders){add_to_Folders(msg);}
Message& Message::operator=(const Message& msg){
this->remove_from_Folders();
contents=msg.contents;
folders=msg.folders;
this->add_to_Folders(msg);
return *this;
}
Message::~Message(){
remove_from_Folders();
}
void Message::save(Folder& f){
f.addMsg(this);
folders.insert(&f);
}
// 13.33
// 不用Folder:避免直接拷贝一个对象,提高性能
// 不加const:在该函数中会对Folder的对象进行insert操作,需要改变它
void Message::remove(Folder& f){
f.remMsg(this);
folders.erase(&f);
}
void Message::add_to_Folders(const Message& msg){
for(auto f:msg.folders)
f->addMsg(this);
}
void Message::remove_from_Folders(){
for(auto f:this->folders)
f->remMsg(this);
}
//-------------------------------------------------
Folder::Folder(const Folder& f)
:msgs(f.msgs){add_to_Message(f);}
Folder& Folder::operator=(const Folder& f){
this->remove_from_Message();
msgs=f.msgs;
this->add_to_Message(f);
return *this;
}
Folder::~Folder(){remove_from_Message();}
void Folder::add_to_Message(const Folder& f){
for(auto i:f.msgs)
i->addFldr(this);
}
void Folder::remove_from_Message(){
for(auto i:this->msgs)
i->remFldr(this);
}
// 13.35
// 书中原话:当我们拷贝一个message时,得到的副本应该与原message出现在相同的Folder中
// 对新拷贝的message对象,如果用的是默认合成拷贝构造函数
// 则新的message不会添加进入那些包含原message的folder中
// 13.38
//@Mooophy: The copy and swap is an elegant way when working with dynamicly allocated memory. In the Message class ,
// nothing is allocated dynamically. Thus using this idiom makes no sense and will make it more complicated to
// implement due to the pointers that point back.
//当涉及到动态分配内存时,拷贝并交换是一个完成该功能的精简的方式.
//但是在Message类中,并未涉及到动态分配内存,这种方法并不会产生任何益处,
//同时还会因为很多指针操作让程序变得更复杂难难以实现
13.39 13.40 13.41 13.43
//StrVec.h
#include
#include
#include
using namespace std;
class StrVec{
public:
StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}
StrVec(initializer_list);
StrVec(const StrVec&);
StrVec& operator=(const StrVec&);
~StrVec(){free();}
void push_back(const string&);
size_t size()const{return first_free-elements;}
size_t capcity()const{return cap-elements;}
string* begin()const{return elements;}
string* end()const {return first_free;}
void reserve(size_t);
void resize(size_t,const string&);
void resize(size_t);
private:
static allocatoralloc;
void chk_n_alloc(){if(size()==capcity())reallocate();}
pair alloc_n_copy(const string*,const string*);
void free();
void reallocate();
string *elements;
string *first_free;
string *cap;
};
//StrVec.cpp
#include"StrVec.h"
#include
allocatorStrVec::alloc;
void StrVec::push_back(const string& s){
chk_n_alloc();
alloc.construct(first_free++,s);
//13.41
//每次创造对象应该在first_free所指向的位置创造
//如果用前置递增则第一次push_back会浪费一个单位的内存没有被构造,同时first_free将指向容器内最后一个有对象的位置
}
pair StrVec::alloc_n_copy(const string* bg,const string* ed){
auto data=alloc.allocate(ed-bg);
return {data,uninitialized_copy(bg,ed,data)};
}
void StrVec::free(){
if(elements){
for(auto p=first_free;p!=elements;)
alloc.destroy(--p);
alloc.deallocate(elements,cap-elements);
}
}
void free2(){ //13.43 此版本更好 不用考虑下标越界,更加简洁
for_each(elements,first_free,[](string& r){alloc.destroy(&r);});
}
StrVec::StrVec(const StrVec& s){
auto newdata=alloc_n_copy(s.begin(),s.end());
elements=newdata.first;
first_free=cap=newdata.second;
}
StrVec& StrVec::operator=(const StrVec& s){
auto newdata=alloc_n_copy(s.begin(),s.end());
free();
elements=newdata.first;
first_free=cap=newdata.second;
return *this;
}
void StrVec::reallocate(){
auto newcapcity=size()?(size()*2):1;
auto newdata=alloc.allocate(newcapcity);
auto old_e=elements;
auto dest=newdata;
for(size_t i=0;icapcity()){
auto newcapcity=n;
auto newdata=alloc.allocate(newcapcity);
auto old_e=elements;
auto dest=newdata;
for(size_t i=0;icapcity())reallocate();
while(first_free!=dest)
alloc.construct(first_free++,str);
}
}
StrVec::StrVec(initializer_listlst){ //13.40
auto newdata=alloc_n_copy(lst.begin(),lst.end());
elements=newdata.first;
first_free=cap=newdata.second;
}
//main.cpp
#include
#include
#include"StrVec.h"
using namespace std;
int main()
{
// 13.39
StrVec sv({"aa","bbb","cccc","gggg"}); //13.40
sv.push_back("ssssssss");
sv.push_back("ddddd");
sv.push_back("eeeeee");
cout<
13.44
#include
#include
#include
using namespace std;
class ChVec{
public:
ChVec():elements(nullptr),cap(nullptr){}
ChVec(const char* ch,size_t len);
ChVec(const ChVec&);
ChVec& operator=(const ChVec&);
~ChVec(){free();}
size_t capacity(){return cap-elements;}
void print(){for(char* p=elements;palloc;
char* elements;
char* cap;
void free(){
if(elements){
size_t len=cap-elements;
while(cap!=elements)
alloc.destroy(--cap);
alloc.deallocate(elements,len);
}
}
pair alloc_n_copy(const char* st,const char* ed){
char* data=alloc.allocate(ed-st);
return {data,uninitialized_copy(st,ed,data)};
}
};
ChVec::ChVec(const char* ch,size_t len){
auto newdata=alloc_n_copy(ch,ch+len);
elements=newdata.first;
cap=newdata.second;
}
ChVec::ChVec(const ChVec& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
elements=newdata.first;
cap=newdata.second;
}
ChVec& ChVec::operator=(const ChVec& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
free();
elements=newdata.first;
cap=newdata.second;
return *this;
}
int main(){
ChVec cv1;
cv1.print();
cout<
13.45 -----13.48
#include
#include
#include
#include
using namespace std;
class String{
public:
String():elements(nullptr),cap(nullptr){}
String(const char* ch,size_t len);
String(const String&);
String& operator=(const String&);
~String(){free();}
size_t capacity(){return cap-elements;}
void print(){for(char* p=elements;palloc;
char* elements;
char* cap;
void free(){
if(elements){
size_t len=cap-elements;
while(cap!=elements)
alloc.destroy(--cap);
alloc.deallocate(elements,len);
}
}
pair alloc_n_copy(const char* st,const char* ed){
char* data=alloc.allocate(ed-st);
return {data,uninitialized_copy(st,ed,data)};
}
};
String::String(const char* ch,size_t len){
auto newdata=alloc_n_copy(ch,ch+len);
elements=newdata.first;
cap=newdata.second;
}
String::String(const String& cv){
auto newdata=alloc_n_copy(cv.elements,cv.cap);
elements=newdata.first;
cap=newdata.second;
cout<<"String(const String& cv)"<vi(100);
int&& r1=f(); //函数返回临时变量
int& r2=vi[0]; //vi[0]是一个变量
int& r3=r1; //r1是一个表达式(左值)
int&& r4=vi[0]*f(); //乘积为临时变量
// 13.48
vectorvec;
char* s="aaaaa";
String str(s,strlen(s));
cout<<"------------"<
13.49
//StrVec
StrVec::StrVec( StrVec&& sv)
:elements(sv.elements),first_free(sv.first_free),cap(sv.cap){
sv.cap=sv.first_free=sv.elements=nullptr;
}
StrVec& StrVec::operator=(StrVec&& sv){
if(this!=&sv){
free();
elements=sv.elements;
first_free=sv.first_free;
cap=sv.cap;
sv.cap=sv.first_free=sv.elements=nullptr;
}
return *this;
}
//String
String::String(String&& st):elements(st.elements),cap(st.cap){
st.elements=st.cap=nullptr;
}
String& String::operator=(String&& st){
if(&st!=this){
free();
elements=st.elements;
cap=st.cap;
st.elements=st.cap=nullptr;
}
return *this;
}
//Message
void Message::move_folder(Message* msg){
folders=std::move(msg->folders);
for(auto f:folders){
f->remMsg(msg);
f->addMsg(this);
}
(msg->folders).clear();
}
Message::Message(Message&& msg):contents(std::move(msg.contents)){
move_folder(&msg);
}
Message& Message::operator=(Message&& msg){
if(this!=&msg){
remove_from_Folders();
contents=std::move(msg.contents);
move_folder(&msg);
}
return *this;
}
13.51----13.54
#include
#include
using namespace std;
class HasPtr{
friend void swap(HasPtr& l,HasPtr& r){
std::swap(l.ps,r.ps);
std::swap(l.i,r.i);
}
public:
HasPtr(const string& s=string()):ps(new string(s)),i(0){cout<<"HasPtr(const string& s=string())"<::type { aka HasPtr }')
// hp1 = std::move(*pH);
return 0;
}
13.55------13.58
#include
#include
#include
#include
using namespace std;
// 13.58
class Foo{
public:
Foo sorted()&&;
Foo sorted()const & ;
private:
vector data;
};
Foo Foo::sorted()&{
sort(data.begin(),data.end());
return *this;
}
// 13.57 函数内部调用&&版本 没有问题
Foo Foo::sorted()const&{
return Foo(*this)sorted();
};
// 13.55
void push_back(string&& s){
data->push_back(std::move(s));
}
// 13.56
//ret是临时创建的变量(左值) ,所以调用sorted即是调用的自己,将会无限递归死循环