1.第13章
1.什么是复制构造函数?什么时候使用?
复制构造函数是一个构造函数,其第一个参数是对类类型的引用,任何其他参数都具有默认值。
当复制初始化发生并且该复制初始化需要复制构造函数或move构造函数时。
使用定义变量 =
将对象作为参数传递给非引用类型的参数
从具有非引用返回类型的函数中返回对象
括号初始化数组中的元素或聚合类的成员
一些类类型还为其分配的对象使用复制初始化。
2.为什么当指向一个对象的引用或者指针离开作用域时,析构函数不会执行。
因为不能保证只有这一个指针要使用对象,如果有其他指针也指向这个对象,删除指针释放内存会导致问题,引用指向的就是那个对象,所以该对象引用不是在作用域新创建的对象。
3.=default显式要求编译器生成合成的版本,只能对默认构造函数或拷贝控制成员、析构函数
4.iostream类阻止了拷贝,避免多个对象写入或读取相同的IO缓冲
阻止拷贝用=delete,=delete可以用于所有成员函数(析构函数除外)
5.std::move是定义在utility头文件中
6.IO类和unique_ptr这样的类包含不能被共享的资源(如指针或IO缓冲),因此,这些类型的对象不能拷贝但可以移动。
7.标准库容器,string和shared_ptr类既能支持移动也支持拷贝。IO类和unique_ptr类可以移动但是不能拷贝
8.一个左值表达式表达的是一个对象的身份,而一个右值表达式表示的是对象的值
9.右值引用可以绑定到一个常量,可以绑定到一个右值表达式,但是不能绑定到左值,变量是一种左值。
10move函数表示将一个左值当做一个右值一样,使用move表示移后源我们不再需要了,移后源对象的值我们现在不能进行任何的假设。
11.移动构造函数完成后,源对象必须不再指向被移动的资源,这些资源的所有权已经归属于新创建的对象
12.拷贝构造操作和移动构造操作的区别
拷贝构造操作是会新建一个内存空间存放成员变量,特别是指针更应该如此。
但是移动构造操作类似于“偷窃”,它直接将一个对象的东西变为自己所有,类似于孙悟空和六耳猕猴,孙悟空和六耳猕猴可能在取经途中互换了身份,最后成佛的是六耳猕猴。但是移后源我们不应该再使用了,它保存的东西也不可假设。
13.只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非static数据成员都可以移动时,编译器才会为它合成移动构造函数或移动赋值运算符。
14.要么都定义移动和拷贝控制,要么定义其中一个会使另一种合成成员函数被定义为删除的。
13.5
class HasPtr {
public:
HasPtr(const std::string& s = std::string()) : ps(new std::string(s)), i(0)
{
}
HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) {}
private:
std::string* ps;
int i;
};
3.13.8
class HasPtr {
public:
HasPtr(const std::string& s = std::string()) : ps(new std::string(s)), i(0)
{
}
HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), i(hp.i) {}
friend HasPtr& operator+(const HasPtr& hp);
private:
std::string* ps;
int i;
};
HasPtr& HasPtr::operator=(const HasPtr& hp):i(hp.i)
{
if(*this == hp)
return *this;
delete ps;
std::string ps = new string(*(hp.ps))
return *this
}
13.11
HasPtr::~HasPtr()
{
delete ps;
//其它存储在栈中的不用管,编译器会隐式释放空间
}
13.18
class Employee
{
private:
std::string name;
long number;
static long snum;
public:
Employee() :name("王二小"),number(snum) {}
Employee(std::string s) :name(s), number(++snum) {};
~Employee() = default;
};
13.26
hpp
using std::vector;
using std::string;
class ConstStrBlobPtr;
class StrBlob
{
typedef vector<string>::size_type size_type;
private:
std::shared_ptr<vector<string>> data;
void check(const size_type &i, const string & msg)const
{
if (i >= data->size())
throw std::out_of_range(msg);
}
public:
friend class ConstStrBlobPtr;
ConstStrBlobPtr begin()const;
ConstStrBlobPtr end() const;
StrBlob() :data(std::make_shared<vector<string>>()) {}
StrBlob(std::initializer_list<string> il): data(std::make_shared<vector<string>>(il)) {}
StrBlob(const StrBlob& sb) :data(std::shared_ptr<vector<string>>(sb.data)) {}
StrBlob operator=(const StrBlob &sb);
size_type size()const { return data->size(); }
bool Empty()const { return data->empty(); }
void push_back(const std::string& s) { data->push_back(s); }
void pop_back() { check(0, "pop_back on empty StrBlob"); data->pop_back(); }
std::string& front()
{
check(0, "front ont empty StrBlob");
return data->front();
}
std::string& back()
{
check(0, "back on empty StrBlob");
return data->front();
}
const std::string& front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
const std::string& back() const
{
check(0, "back on empty StrBlob");
return data->back();
}
};
class ConstStrBlobPtr
{
public:
ConstStrBlobPtr() :curr(0) {}
ConstStrBlobPtr(const StrBlob& a, size_t sz = 0) :wptr(a.data), curr(sz) {}
bool operator!=(ConstStrBlobPtr& p) { return p.curr != curr; }
const string& deref()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
ConstStrBlobPtr& incr()
{
check(curr, "increnment past end of StrBlobPtr");
++curr;
return *this;
}
private:
std::weak_ptr<vector<string>> wptr;
size_t curr;
std::shared_ptr <vector<string>> check(size_t i, const string& msg)const
{
auto ret = wptr.lock();
if (!ret)throw std::runtime_error("unbound StrBlobPtr");
if (i >= ret->size()) throw std::out_of_range(msg);
return ret;
}
};
cpp
ConstStrBlobPtr StrBlob::begin() const // should add const
{
return ConstStrBlobPtr(*this);
}
ConstStrBlobPtr StrBlob::end() const // should add const
{
return ConstStrBlobPtr(*this, data->size());
}
StrBlob& StrBlob::operator=(const StrBlob& sb)
{
data = std::make_shared<vector<string>>(*sb.data);
return *this;
}
13.39
hpp
using std::vector;
using std::string;
class ConstStrBlobPtr;
class StrVec
{
public:
StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec &operator=(const StrVec&);
~StrVec();
void push_back(const std::string &);
size_t size()const { return first_free-elements; }
size_t capacity()const { return cap - elements; }
std::string *begin()const { return elements; }
std::string*end()const { return first_free; }
private:
static std::allocator<std::string> alloc;
void chk_n_alloc() { if (size() == capacity()) reallocate(); }
std::pair<std::string*, std::string*>alloc_n_copy(const std::string *,const std::string* );
void free();
void reallocate();
std::string *elements;
std::string *first_free;
std::string *cap;
};
cpp
using namespace std;
void StrVec::push_back(const std::string &s)
{
chk_n_alloc();
alloc.construct(first_free++, s);
}
pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string *b, const std::string*e)
{
auto data = alloc.allocate(e - b);//分配的是指针指向的地址
return { data,uninitialized_copy(b,e,data) };
}
void StrVec::free()
{
if (elements)
{
for (auto p = first_free; p != elements;p--)
alloc.destroy(p);
alloc.deallocate(elements, cap - elements);
}
}
StrVec::StrVec(const StrVec&s)
{
auto newdata = alloc_n_copy(s.begin(), s.end());
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::~StrVec()
{
free();
}
StrVec &StrVec::operator=(const StrVec&s)
{
free();
auto data = alloc_n_copy(s.begin(), s.end());
first_free = data.first;
first_free = cap = data.second;
return *this;
}
void StrVec::reallocate()
{
auto newcapacity = size() ? 2 * size() : 0;
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata;//指向新数组中下一个空闲位置
auto elem = elements;//指向旧数组中下一个元素
for (size_t i = 0; i != size(); ++i)
alloc.construct(dest++, std::move(*elem++));
free();
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
2.第14章
14.2
friend ostram & Sales_data::operator>>(ostream &os,Sales_data &Sd);
friend istream & Sales_data::operator<<(istream &is,Sales_data &Sd);
Sales_data& Sd Sales_data::operator+(const Sales_data& );
Sales_data& Sd Sales_data::operator+=(const Sales_data& );
14.3
a都不是,bstring,cvector,dstring
14.4
(a) symmetric operator. Hence, non-member
(b) changing state of objects. Hence, member
© changing state of objects. Hence, member
(d) = -> must be member
(e) non-member
(f) symetric , non-member
(g) symetric , non-member
(h) must be member