C++ Primer问题总结(8)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值