C++Primer13.6.2节练习

练习13.49:

StrVec类的移动构造函数和移动赋值运算符

//移动构造函数
StrVec::StrVec(StrVec&& s)noexcept :elements(s.elements), first_free(s.first_free), cap(s.cap)
{
	//令移后源对象进入状态-----对其运行析构函数是安全的
	s.elements = s.first_free = s.cap = nullptr;
}

//移动赋值运算符
StrVec& StrVec::operator=(StrVec&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	return *this;
}

String类的移动构造函数和移动赋值运算符

//移动构造函数
String::String(String&& s)noexcept:elements(s.elements),first_free(s.first_free),cap(s.cap)
{
	//令移后源对象进入状态-----对其运行析构函数是安全的
	s.elements = s.first_free = s.cap = nullptr;
}

//移动赋值运算符
String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	return *this;
}

Message类的移动构造函数和移动赋值运算符

void Message::move_Folders(Message* m)
{
	//使用set的移动赋值运算符
	folders = std::move(m->folders);
	//遍历每一个fFolder,从中删除旧的Message
	//将本Message添加到Folder中
	for (auto f : folders)
	{
		f->remMsg(m);
		f->addMsg(this);
	}
	//确保销毁m是无害的
	m->folders.clear();
}

//移动构造函数
Message::Message(Message&& m) :contents(std::move(m.contents))
{
	move_Folders(&m);
}

//移动赋值运算符
Message& Message::operator=(Message&& rhs)
{
	//检查自赋值情况
	if (this != &rhs)
	{
		//将本Message从所有的Folders中删除
		remove_from_Folders();
		//移动赋值
		contents = std::move(rhs.contents);
		//更新Folders
		move_Folders(&rhs);
	}

	return *this;
}

练习13.50:

向String类的移动构造函数和移动赋值运算符中添加打印语句

//移动构造函数
String::String(String&& s)noexcept:elements(s.elements),first_free(s.first_free),cap(s.cap)
{
	//令移后源对象进入状态-----对其运行析构函数是安全的
	s.elements = s.first_free = s.cap = nullptr;
	cout << "------String move constructor------" << endl;
}

//移动赋值运算符
String& String::operator=(String&& rhs)noexcept
{
	if (this != &rhs)
	{
		free();
		elements = rhs.elements;
		first_free = rhs.first_free;
		cap = rhs.cap;
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	cout << "------String move assignment operator------" << endl;
	return *this;
}

测试代码

int main()
{
	//测试
	String s1("hello ");
	String s2("world!!!");
	String s3("C++");
	vector<String>vs;
	//移动构造
	String s4(std::move(s2));
	String s5(std::move(s1));

	//移动赋值运算符
	s2 = std::move(s3);
	system("pause");
	return 0;
}

结果

 练习13.51:

返回的是即将销毁的临时变量unique_ptr,是一个右值绑定的引用,所以这不是拷贝,而是移动,窃取资源而不是拷贝资源,所以是合法的

练习13.52:

在第一个赋值中,右侧运算对象是一个左值,因此移动构造函数是不可行的。rhs将使用拷贝构造函数来初始化。拷贝构造函数将分配一个新string,并拷贝 hp2指向的string
在第二个赋值中,我们调用std: : move 将一个右值引用绑定到hp2上。在此情况下,拷贝构造函数和移动构造函数都是可行的。但是,由于实参是一个右值引用,移动构造函数是精确匹配的。移动构造函数从hp2拷贝指针,而不会分配任何内存
不管使用的是拷贝构造函数还是移动构造函数,赋值运算符的函数体都swap两个运算对象的状态。交换HasPtr 会交换两个对象的指针(及int)成员。在swap 之后,rhs中的指针将指向原来左侧运算对象所拥有的 string。当rhs离开其作用域时,这个string将被销毁

练习13.53:

赋值运算符如下:


//赋值运算符既是移动赋值运算符,也是拷贝赋值运算符
HasPtr& HasPtr::operator=(HasPtr rhs)
{
	swap(*this, rhs);
	return *this;
}

对于拷贝赋值,首先要拷贝构造rhs(左值),然后swap

对于移动赋值,首先要移动构造rhs(右值),然后swap

都需要进行rhs的构造,性能不高

新的移动赋值运算符和移动构造函数如下

//拷贝赋值运算符
HasPtr& HasPtr::operator=(const HasPtr& rhs)
{
	if (this != &rhs)
	{
		delete ps;
		swap(*this, rhs);
	}
	return *this;
}


//移动赋值运算符
HasPtr& HasPtr::operator=(HasPtr&& rhs)noexcept
{
	if (this != &rhs)
	{
		delete ps;
		//移动元素
		ps = rhs.ps;
		i = rhs.i;
		rhs.ps = nullptr;
	}
	return *this;
}


练习13.54:

运行错误,产生二义性,传入的参数与两个函数都发生匹配

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白学C++.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值