C++Primer第五版 第十三章习题答案(51~58)

51:P418已经说的很清楚,使用的是移动操作,因为返回值相当于一个表达式,为右值


52:rhs是一个非引用的参数,所以需要进行拷贝初始化,依赖于实参的类型,拷贝初始化要么使用拷贝构造函数要么使用移动构造函数,左值被拷贝,右值被移动

hp的第一个赋值中,右侧为左值,需要进行拷贝初始化,分配一个新的string,并拷贝hp2所指向的string

hp的第二个赋值中,直接调用std::move()将一个右值绑定到hp2上,虽然移动构造函数和拷贝构造函数皆可行,但是移动构造函数是精确匹配且不会分配任何内存


53:需要支持C++11新标准

#include  
#include
#include
#include
using namespace std;

class Hasptr1
{
	friend void swap(Hasptr1&,Hasptr1&);
	friend bool operator<(const Hasptr1& s1,const Hasptr1& s2);
	friend void show(vector& vec);
public:
	//构造函数,初始化相关成员
	Hasptr1(const string& s = string()):ps(new string(s)),i(0),use(new size_t(1)){}

	//拷贝构造函数,将引用计数也拷贝过来,并且递增引用计数
	Hasptr1(const Hasptr1& p):ps(p.ps),i(p.i),use(p.use){++*use;}

	//拷贝赋值运算符
	Hasptr1& operator= (const Hasptr1& p1)
	{
		++*p1.use;//首先递增右侧运算符对象的引用计数
		if (--*use == 0)//递减本对象的引用计数,若没有其他用户,则释放本对象的成员
		{
			delete ps;
			delete use;
		}
		ps = p1.ps;//进行拷贝
		use = p1.use;
		i = p1.i;
		return *this;
	}

	Hasptr1(Hasptr1&& p) noexcept : ps(p.ps), i(p.i)
	{
		p.ps = 0;
		std::cout << "call move constructor" << std::endl;
	}

	Hasptr1& operator=(Hasptr rhs)
	{
		swap(*this, rhs);
		return *this;
	}

	// Hasptr1& operator=(const Hasptr1 &rhs)
	//{
	//    auto newp = new std::string(*rhs.ps);
	//    delete ps;
	//    ps = newp;
	//    i = rhs.i;
	//    std::cout << "call copy assignment" << std::endl;
	//    return *this;
	//}

	// Hasptr& operator=(Hasptr1 &&rhs) noexcept
	//{
	//    if (this != &rhs)
	//    {
	//        delete ps;
	//        ps = rhs.ps;
	//        i = rhs.i;
	//        rhs.ps = nullptr;
	//        std::cout << "call move assignment" << std::endl;
	//    }
	//    return *this;
	//}
	//析构函数
	~Hasptr1()
	{
		if (*use == 0)//引用计数变为0,说明已经没有对象再需要这块内存,进行释放内存操作
		{
			delete ps;
			delete use;
		}
	}
private:
	//定义为指针,是我们想将该string对象保存在动态内存中
	string *ps;
	size_t *use;//将计数器的引用保存
	int i;
};

inline void swap(Hasptr1& a,Hasptr1& b)
{
	using std::swap;
	swap(a.ps,b.ps);
	std::swap(a.i,b.i);
	cout<<"123";
}

bool operator< (const Hasptr1& s1,const Hasptr1& s2)
{
	cout<<"定义的 Operator< 被调用"<& vec)
{
	vector::iterator it1 = vec.begin();
	for (it1; it1 != vec.end(); ++it1)
	{
		cout<<*(it1->ps)< vec1;
// 	Hasptr1 a("l");
// 	Hasptr1 b("llll");
// 	Hasptr1 c("lll");
// 	vec1.push_back(a);
// 	vec1.push_back(b);
// 	vec1.push_back(c);
// 	vector::iterator it1 = vec1.begin();
// 	sort(vec1.begin(),vec1.end());
// 	show(vec1);


	Hasptr1 hp1("hello"), hp2("World"), *pH = new Hasptr1("World");
	hp1 = hp2;
	hp1 = std::move(*pH);
	return 0;
}  


54:见53代码


55:知识点1:区分拷贝和移动的重载函数通常有一个版本接收const T &(左值引用),一个版本接受T&&(右值引用参数)——引用限定符,这样我们调用函数时,实参的类型决定了新元素是进行拷贝还是移动操作

知识点2:在函数的参数列表之后加上&或者&&表示该函数只能用于左值或者右值

知识点3:当我们定义两个或两个以上的具有同名且参数列表相同的成员函数,必须对所有函数都加上引用限定符或者都不加

void push_back(string &&s) { data->push_back(move(s)); }


56:sorted不断调用本身,无限循环,造成堆栈溢出


57:见58


58:

#include 
#include 
#include 

using std::vector;
using std::sort;

class Foo {
public:
	Foo sorted()&&;
	Foo sorted() const&;

private:
	vector data;
};

Foo Foo::sorted() &&
{
	sort(data.begin(), data.end());
	std::cout << "&&" << std::endl; // debug
	return *this;
}

Foo Foo::sorted() const &
{
	//    Foo ret(*this);
	//    sort(ret.data.begin(), ret.data.end());
	//    return ret;

	std::cout << "const &" << std::endl; // debug

	//    Foo ret(*this);
	//    ret.sorted();     //13.56
	//    return ret;

	return Foo(*this).sorted(); //13.57
}

int main()
{
	Foo().sorted(); // call "&&"
	Foo f;
	f.sorted(); // call "const &"
}




你可能感兴趣的:(【C++Primer习题】,C++Primer,第五版习题答案详解)