虽然 unique_ptr 不能拷贝,但我们在12.1.5节中编写了一个 clone 函数,它以值的方式返回一个 unique_ptr。解释为什么函数是合法的,以及为什么它能正确工作。
在这里是移动的操作而不是拷贝操作,因此是合法的。
详细解释第478页中的 HasPtr 对象的赋值发生了什么?特别是,一步一步描述 hp、hp2 以及 HasPtr 的赋值运算符中的参数 rhs 的值发生了什么变化。
左值被拷贝,右值被移动。
从底层效率的角度看,HasPtr 的赋值运算符并不理想,解释为什么?为 HasPtr 实现一个拷贝赋值运算符和一个移动赋值运算符,并比较你的新的移动赋值运算符中执行的操作和拷贝并交换版本中的执行的操作。
#ifndef CP5_ex13_53_h
#define CP5_ex13_53_h
#include
class HasPtr
{
public:
friend void swap(HasPtr&, HasPtr&);
HasPtr(const std::string &s = std::string());
HasPtr(const HasPtr &hp);
HasPtr(HasPtr &&p) noexcept;
HasPtr& operator=(HasPtr rhs);
//HasPtr& operator=(const HasPtr &rhs);
//HasPtr& operator=(HasPtr &&rhs) noexcept;
~HasPtr();
private:
std::string *ps;
int i;
};
#endif // CP5_ex13_53_h
#include "exercise13_53.h"
#include
inline void swap(HasPtr &lhs, HasPtr &rhs)
{
using std::swap;
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
std::cout << "call swap" << std::endl;
}
HasPtr::HasPtr(const std::string &s) : ps(new std::string(s)), i(0)
{
std::cout << "call constructor" << std::endl;
}
HasPtr::HasPtr(const HasPtr &hp) : ps(new std::string(*hp.ps)), i(hp.i)
{
std::cout << "call copy constructor" << std::endl;
}
HasPtr::HasPtr(HasPtr &&p) noexcept : ps(p.ps), i(p.i)
{
p.ps = 0;
std::cout << "call move constructor" << std::endl;
}
HasPtr& HasPtr::operator=(HasPtr rhs)
{
swap(*this, rhs);
return *this;
}
HasPtr::~HasPtr()
{
std::cout << "call destructor" << std::endl;
delete ps;
}
如果我们为 HasPtr 定义了移动赋值运算符,但未改变拷贝并交换运算符,会发生什么?编写代码验证你的答案。
error: ambiguous overload for 'operator=' (operand types are 'HasPtr' and 'std::remove_reference::type { aka HasPtr }')
hp1 = std::move(*pH);
^
为你的 StrBlob 添加一个右值引用版本的 push_back。
void push_back(string &&s) { data->push_back(std::move(s)); }
如果 sorted 定义如下,会发生什么?
Foo Foo::sorted() const & {
Foo ret(*this);
return ret.sorted();
}
会产生递归并且最终溢出。
如果 sorted定义如下,会发生什么:
Foo Foo::sorted() const & { return Foo(*this).sorted(); }
没问题。会调用移动版本。
编写新版本的 Foo 类,其 sorted 函数中有打印语句,测试这个类,来验证你对前两题的答案是否正确。
#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(); // Exercise 13.56
// return ret;
return Foo(*this).sorted(); // Exercise 13.57
}
int main()
{
Foo().sorted(); // call "&&"
Foo f;
f.sorted(); // call "const &"
}