练习 13.1:
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数;
- 使用=定义变量
- 将一个对象作为实参传递给一个非引用类型的形参
- 从一个返回类型为非引用的函数返回一个对象
- 用花括号列表初始化一个数组中的元素或一个聚合类中的成员
- 某些类类型还会对它们所分配的对象使用拷贝初始化。
练习 13.2:
拷贝构造函数自己的参数必须是引用类型。如果其参数不是引用类型,则调用永远也不会成功——为了调用拷贝构造函数,我们必须拷贝他的实参,但为了拷贝实参,我们又需要调用拷贝构造函数,如此无限循环。
练习 13.3:
当我们拷贝一个StrBlob时,shared_ptr成员的use_count增加一。拷贝StrBlobPrts时,weak_ptr成员的use_count不会改变。(因为use_count是shared_ptr的数量)
练习 13.4:
Point global;
Point foo_bar(Point arg) // 1 实参传递给非引用类型的形参
{
Point local = arg, *heap = new Point(global); // 2, 3 =定义变量
*heap = local; // 4 =定义变量
Point pa[ 4 ] = { local, *heap }; // 5 花括号列表初始化一个数组中的元素
return *heap; // 6 从一个返回类型为非引用类型的函数返回一个对象
}
练习 13.5:
class HasPtr
{
public:
HasPtr(const string& s = string()): ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp): ps(new string(*hp.ps)), i(hp.i){}
private:
string* ps;
int i;
};
练习 13.6:
拷贝赋值运算符就是一个名为operator=的函数。当发生赋值时使用此操作符。对于某些类,合成拷贝赋值运算符用来禁止该类型对象的赋值。如果拷贝赋值运算符并非出于此目的,它会将右侧对象的每个非static成员赋值给左侧运算对象的对应成员。当一个类没有定义自己的拷贝赋值运算符的时候,编译器会为它生成一个合成拷贝赋值运算符。
练习 13.7:
在这两种情况下,都会发生浅拷贝。所有的指针都指向同一个地址。use_count的变化与练习13.3相同。
练习 13.8:
class HasPtr
{
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(const HasPtr& hp)
{
delete ps;
ps = new string(*hp.ps);
i = hp.i;
return *this;
}
private:
string* ps;
int i;
};
练习 13.9:
析构函数是类的一个成员函数,名字由波浪号接类名构成。类似拷贝构造函数和拷贝赋值运算符,对于某些类,合成析构函数被用来阻止该类型对象的销毁。如果不是这种情况,合成析构函数的函数体为空。当一个类没有定义自己析构函数时,编译器会为它定义一个合成析构函数。
练习 13.10:
当StrBlob对象销毁时,动态对象的use_count将递减。如果该动态对象没有shared_ptr,它将被释放。当StrBlobPtr对象销毁时,动态分配的对象不会被释放。
练习 13.11:
#include<iostream>
using namespace std;
class HasPtr
{
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(const HasPtr& hp)
{
auto newp = new string(*hp.ps);
delete ps;
ps = newp;
i = hp.i;
return *this;
}
//HasPtr& operator=(const HasPtr& hp)
//{
// delete ps;
// // 如果hp和*this是同一个对象,我们就将从已释放的内存中拷贝数据
// ps = new string(*hp.ps);
// i = hp.i;
// return *this;
//}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
练习 13.12:
用于item2拷贝初始化的临时对象accum,函数体中构造的两个对象item1和item2。当指向一个对象的引用或指针离开作用域时,析构函数不会执行。
练习 13.13:
#include <iostream>
#include <vector>
using namespace std;
struct X {
X() { cout << "X()" << endl; }
X(const X&) { cout << "X(const X&)" << endl; }
X& operator= (const X&)
{
cout << "X& operator=(const X&)" << endl;
return *this;
}
~X() { cout << "~X()" << endl; }
};
void fun1(X p) { ; } // 非引用参数传递
void fun2(X& p) { ; } // 引用参数传递
int main(int argc, char* argv[])
{
cout << "默认初始化:" << endl;
X x; // 执行默认构造函数
cout << "传递非引用参数:" << endl;
fun1(x); // 执行拷贝构造函数和析构函数
cout << "传递引用参数:" << endl;
fun2(x); // 构造函数和析构函数不会执行
cout << "动态分配对象并销毁:" << endl;
X* p = new X; // 执行默认构造函数
delete p; // 执行析构函数
cout << "添加到容器:" << endl;
vector<X> vx;
vx.push_back(x); // 执行拷贝构造函数
cout << "拷贝初始化:" << endl;
X y = x; // 执行拷贝构造函数
cout << "拷贝赋值:" << endl;
y = x; // 执行拷贝赋值运算符
// 函数执行完毕,执行析构函数销毁x, y和vx中的元素
return 0;
}
练习 13.14:
程序输出结果都是一样的,都是对象a的mysn成员。
练习 13.15:
输出结果将会改变。因为我们不使用合成的拷贝控制成员,而是使用自己定义的。函数f传入的是对象的拷贝,所以其输出的值是临时对象的数据成员。输出将是三个不同的数字。
练习 13.16:
输出结果将会改变。此时函数f传入的不再是对象的拷贝而是对象的引用,所以其输出的值也不是临时对象的数据成员,而是原本的数据成员。
练习 13.17:
// 练习 13.14:
#include<iostream>
using namespace std;
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
int mysn;
};
void f(numbered s) { cout << s.mysn << endl; }
int main()
{
numbered a, b = a, c = b;
f(a); f(b); f(c); // a = b = c = 10
return 0;
}
// 练习 13.15:
#include<iostream>
using namespace std;
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
numbered(const numbered& n) { mysn = n.mysn + 1; }
int mysn;
};
void f(numbered s) { cout << s.mysn << endl; }
int main()
{
numbered a, b = a, c = b; // a = 10; b = 11; c = 12
f(a); f(b); f(c); // 'a' = 11; 'b' = 12; 'c' = 13
return 0;
}
// 练习 13.16:
#include<iostream>
using namespace std;
class numbered
{
public:
numbered()
{
static int unique = 10;
mysn = unique++;
}
numbered(const numbered& n) { mysn = n.mysn + 1; }
int mysn;
};
void f(const numbered& s) { cout << s.mysn << endl; }
int main()
{
numbered a, b = a, c = b; // a = 10; b = 11; c = 12
f(a); f(b); f(c); // a = 10; b = 11; c = 12
return 0;
}
练习 13.18:
#include<iostream>
using namespace std;
class Employee
{
public:
Employee() { m_id = s_increment++; }
Employee(const string& name)
{
this->m_id = s_increment++;
this->m_name = name;
}
const int id() const { return this->m_id; }
private:
string m_name;
int m_id;
static int s_increment; //static成员类内声明类外定义,在类外定义时不加static
};
int Employee::s_increment = 0;
练习 13.19:
不需要,因为在逻辑上不合理。员工不能复制在现实世界中,所以应该把拷贝控制成员定义为删除的。
#include<iostream>
using namespace std;
class Employee
{
public:
Employee() { m_id = s_increment++; }
Employee(const string& name)
{
this->m_id = s_increment++;
this->m_name = name;
}
Employee(const Employee&) = delete;
Employee& operator=(const Employee&) = delete;
const int id() const { return this->m_id; }
private:
string m_name;
int m_id;
static int s_increment;
};
int Employee::s_increment = 0;
int main()
{
Employee e;
cout << e.id() << endl;
}
练习 13.20:
使用合成版本的拷贝控制成员对对象进行拷贝、赋值或销毁。
练习 13.21:
由于合成版本满足这种情况下的所有需求,因此不需要定义自定义版本的拷贝控制成员。
练习 13.22:
#include<iostream>
using namespace std;
class HasPtr
{
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(const HasPtr& hp)
{
auto newp = new string(*hp.ps);
delete ps;
ps = newp;
i = hp.i;
return *this;
}
//HasPtr& operator=(const HasPtr& hp)
//{
// delete ps;
// // 如果hp和*this是同一个对象,我们就将从已释放的内存中拷贝数据!
// ps = new string(*hp.ps);
// i = hp.i;
// return *this;
//}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
练习 13.23:
对于一个赋值运算符来说,正确工作是非常重要的,即使是将一个对象赋予它自身,也要能正确工作。一个好的方法是在销毁左侧运算对象资源之前拷贝右侧运算对象。
练习 13.24:
如果HasPtr没有定义析构函数,就会发生内存泄漏,因为成员变量ps是动态分配的对象,需要使用delete显式的去释放。如果HasPtr没有定义拷贝构造函数,可能会造成指针被delete两次,或使用悬空指针的情况。因为,使用合成的拷贝构造函数和拷贝复制运算符,只是简单拷贝指针成员,这意味着多个HasPtr对象可能指向相同的内存。
练习 13.25:
拷贝构造函数和拷贝赋值运算符应该动态地为自己分配内存,而不是与右侧对象共享数据。
不需要析构函数是因为shared_ptr调用自己的析构函数来释放动态分配的内存。
练习 13.26:
#include<iostream>
#include<string>
#include<vector>
#include<memory>
#include<fstream>
using namespace std;
class ConstStrBlobPtr;
// StrBlob类
class StrBlob
{
public:
typedef vector<string>::size_type size_type;
friend class ConstStrBlobPtr;
ConstStrBlobPtr begin()const;
ConstStrBlobPtr end()const;
StrBlob() : data(make_shared<vector<string>>()) { }
StrBlob(initializer_list<string> il) :
data(make_shared<vector<string>>(il)) { }
// 拷贝构造函数
StrBlob(const StrBlob& sb): data(make_shared<vector<string>>(*sb.data)){}
// 拷贝赋值运算符
StrBlob& operator=(const StrBlob& sb)
{
this->data = make_shared<vector<string>>(*sb.data);
return *this;
}
size_type size()const { return data->size(); }
bool empty()const { return data->empty(); }
void push_back(const string& t) { data->push_back(t); }
void pop_back()
{
check(0, "pop_back on empty StrBlob");
data->pop_back();
}
string& front()
{
check(0, "front on empty StrBlob");
return data->front();
}
const string& front()const
{
check(0, "front on empty StrBlob");
return data->front();
}
string& back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const string& back()const
{
check(0, "back on empty StrBlob");
return data->back();
}
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string& msg)const
{
if (i >= data->size())
throw out_of_range(msg);
}
};
class ConstStrBlobPtr
{
public:
ConstStrBlobPtr() : curr(0) {}
ConstStrBlobPtr(const StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) {}
bool operator!=(const ConstStrBlobPtr& p) { return p.curr != curr; }
const string& deref()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
ConstStrBlobPtr& incr()
{
check(curr, "increment past end of ConstStrBlobPtr");
++curr;
return *this;
}
private:
shared_ptr<vector<string>> check(size_t i, const string& msg)const
{
auto ret = wptr.lock();
if (!ret)
throw runtime_error("unbound ConstStrBlobPtr");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
weak_ptr<vector<string>> wptr;
size_t curr;
};
ConstStrBlobPtr StrBlob::begin()const { return ConstStrBlobPtr(*this); }
ConstStrBlobPtr StrBlob::end()const { return ConstStrBlobPtr(*this, data->size()); }
练习 13.27:
#include<iostream>
#include<string>
using namespace std;
class HasPtr
{
public:
// 构造函数分配新的string和新的计数器,将计数器置为1
HasPtr(const string& s = string()) :
ps(new string(s)), i(0), use(new size_t(1)) {}
HasPtr(const HasPtr& rhs) :
ps(rhs.ps), i(rhs.i), use(rhs.use) { ++*use; }
HasPtr& operator=(const HasPtr& rhs)
{
// 递增右侧运算对象的引用计数
++*use;
// 递减本对象的引用计数,如果引用计数为0,释放释放ps和use的内存
if (--*use == 0)
{
delete ps;
delete use;
}
// 将数据从rhs拷贝到本对象
this->ps = rhs.ps;
this->i = rhs.i;
this->use = rhs.use;
return *this;
}
~HasPtr()
{
// 如果引用计数变为0,释放ps和use的内存
if (--*use == 0)
{
delete ps;
delete use;
}
}
private:
string* ps;
int i;
size_t* use; // 用来记录有多少对象共享*ps的成员
};
练习 13.28:
#include<iostream>
#include<string>
using namespace std;
class TreeNode
{
public:
TreeNode(const string& val = string(), int c = 0, TreeNode* l = nullptr, TreeNode* r = nullptr) :
value(val), count(c), left(new TreeNode(*l)), right(new TreeNode(*r)) {}
TreeNode(const TreeNode& rhs) :
value(rhs.value), count(rhs.count)
{
if (rhs.left != nullptr)
left = new TreeNode(*rhs.left);
else
left = nullptr;
if (rhs.right != nullptr)
right = new TreeNode(*rhs.right);
else
right = nullptr;
}
TreeNode& operator=(const TreeNode& rhs)
{
value = rhs.value;
count = rhs.count;
if (rhs.left != nullptr)
{
auto newl = new TreeNode(*rhs.left);
delete left;
left = newl;
}
else
{
delete left;
left = nullptr;
}
if (rhs.right != nullptr)
{
auto newr = new TreeNode(*rhs.right);
delete right;
right = newr;
}
else
{
delete right;
right = nullptr;
}
return *this;
}
~TreeNode()
{
delete left;
delete right;
}
private:
string value;
int count;
TreeNode* left;
TreeNode* right;
};
class BinStrTree
{
public:
BinStrTree(): root(new TreeNode()){}
BinStrTree(const BinStrTree& rhs): root(new TreeNode(*rhs.root)){}
BinStrTree& operator=(const BinStrTree& rhs)
{
auto new_root = new TreeNode(*rhs.root);
delete root;
root = new_root;
return *this;
}
~BinStrTree() { delete root; }
private:
TreeNode* root;
};
练习 13.29:
因为该类中的数据成员是内置类型的,而内置类型是没有特定版本的swap的,所以对swap的调用会调用标准库的std::swap。
练习 13.30:
#include<iostream>
#include<string>
using namespace std;
class HasPtr
{
friend ostream& print(ostream& os, HasPtr& hp);
friend void swap(HasPtr& lhs, HasPtr& rhs);
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(const HasPtr& hp)
{
auto newp = new string(*hp.ps);
delete ps;
ps = newp;
i = hp.i;
return *this;
}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
ostream& print(ostream& os, HasPtr& hp)
{
os << *hp.ps << " " << hp.i;
return os;
}
inline
void swap(HasPtr& lhs, HasPtr& rhs)
{
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
cout << "use swap(HasPtr& lhs, HasPtr& rhs)" << endl;
}
int main()
{
HasPtr hp1("Cpp");
HasPtr hp2("Java");
print(cout, hp1) << endl;
print(cout, hp2) << endl;
swap(hp1, hp2);
print(cout, hp1) << endl;
print(cout, hp2) << endl;
}
练习 13.31:
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
using namespace std;
class HasPtr
{
friend ostream& print(ostream& os, HasPtr& hp);
friend void swap(HasPtr& lhs, HasPtr& rhs);
friend bool operator<(const HasPtr& lhs, const HasPtr& rhs);
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i) {}
HasPtr& operator=(HasPtr hp) // 值传递,不改变实参
{
swap(*this, hp);
return *this;
}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
ostream& print(ostream& os, HasPtr& hp)
{
os << *hp.ps << " " << hp.i;
return os;
}
inline
void swap(HasPtr& lhs, HasPtr& rhs)
{
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
cout << "use swap(HasPtr& lhs, HasPtr& rhs)" << endl;
}
inline
bool operator<(const HasPtr& lhs, const HasPtr& rhs)
{
return *lhs.ps < *rhs.ps;
}
int main()
{
vector<HasPtr> hp_vec;
string word;
while (cin >> word)
hp_vec.push_back(HasPtr(word));
for (auto& elem : hp_vec)
print(cout, elem) << endl;
sort(hp_vec.begin(), hp_vec.end());
for (auto& elem : hp_vec)
print(cout, elem) << endl;
return 0;
}
在赋值运算符中使用swap,调用sort的时候会执行swap。
练习 13.32:
类值的HasPtr版本使用swap函数交换指针,而不是分配string的副本,从而避免内存分配是swap函数提高性能的原因。类指针的HasPtr版本交换的数据成员原本就是指针和整型,并没有优化的效果,所以没有得到益处。
练习 13.33:
因为这些操作会改变给定的Folder。Folder类通过它的addMsg和remMsg成员分别添加或删除给定Message的指针。
练习 13.34 && 13.36 && 13.37:
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
using namespace std;
class Folder;
class Message
{
friend class Folder;
friend void swap(Message& lhs, Message& rhs);
public:
Message(const string& str = ""): contents(str){}
Message(const Message&);
Message& operator=(const Message&);
~Message();
// 从给定Folder集合中添加/删除本Message
void save(Folder&);
void remove(Folder&);
void print() { cout << contents << endl; }
private:
string contents; // 实际消息文本
set<Folder*> folders; // 包含本message的folder
// 将本Message添加到指向参数的Folder中
void add_to_Folders(const Message&);
// 从folders中的每个folder中删除本Message
void remove_from_Folders();
void addFldr(Folder* f) { this->folders.insert(f); }
void remFldr(Folder* f) { this->folders.erase(f); }
};
class Folder
{
friend class Message;
friend void swap(Folder& lhs, Folder& rhs);
public:
Folder() = default;
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder();
void print()
{
for (auto m : this->msgs)
cout << m->contents << " ";
cout << endl;
}
private:
set<Message*> msgs;
void add_to_Message(const Folder&);
void remove_from_Message();
void addMsg(Message* m) { msgs.insert(m); }
void remMsg(Message* m) { msgs.erase(m); }
};
// Message类的成员函数
// 将本Message添加到指向参数的Folder中
void Message::add_to_Folders(const Message& m)
{
for (auto f : m.folders) // 对每个包含m的folder
f->addMsg(this); // 向该folder添加一个指向本Message的指针
}
// 拷贝构造
Message::Message(const Message& rhs): contents(rhs.contents), folders(rhs.folders)
{
this->add_to_Folders(rhs);
}
// 从对应的folders中删除本Message
void Message::remove_from_Folders()
{
for (auto f : this->folders)// 对于folders中每个指针
f->remMsg(this); // 从该folder中删除本message
}
// 析构
Message::~Message()
{
this->remove_from_Folders();
}
// 拷贝赋值
Message& Message::operator=(const Message& rhs)
{
this->remove_from_Folders();
this->contents = rhs.contents;
this->folders = rhs.folders;
this->add_to_Folders(rhs); // 将本Message添加到那些Folder中
return *this;
}
// 从给定Folder集合中添加本Message
void Message::save(Folder& f)
{
this->folders.insert(&f);
f.addMsg(this);
}
// 从给定Folder集合中删除本Message
void Message::remove(Folder& f)
{
this->folders.erase(&f);
f.remMsg(this);
}
void swap(Message& lhs, Message& rhs)
{
// 将每个消息的指针从它(旧)所在Folder中删除
lhs.remove_from_Folders();
rhs.remove_from_Folders();
// 交换contents和Folder指针
swap(lhs.contents, rhs.contents);
swap(lhs.folders, rhs.folders);
// 将每个Message的指针添加到它的(新)Folder中
lhs.add_to_Folders(lhs);
rhs.add_to_Folders(rhs);
}
// Folder类的成员函数
void Folder::add_to_Message(const Folder& f)
{
for (auto m : f.msgs)
m->addFldr(this);
}
// 拷贝构造
Folder::Folder(const Folder& rhs): msgs(rhs.msgs)
{
this->add_to_Message(rhs);
}
void Folder::remove_from_Message()
{
for (auto m : this->msgs)
m->remFldr(this);
}
// 析构
Folder::~Folder()
{
this->remove_from_Message();
}
// 拷贝赋值
Folder& Folder::operator=(const Folder& rhs)
{
this->remove_from_Message();
this->msgs = rhs.msgs;
this->add_to_Message(rhs);
return *this;
}
void swap(Folder& lhs, Folder& rhs)
{
lhs.remove_from_Message();
rhs.remove_from_Message();
swap(lhs.msgs, rhs.msgs);
lhs.add_to_Message(lhs);
rhs.add_to_Message(rhs);
}
int main()
{
Message msg1("Cpp");
Message msg2("Java");
msg1.print();
msg2.print();
Folder fldr;
msg1.save(fldr);
msg2.save(fldr);
fldr.print();
msg1 = msg1;
msg1.print();
fldr.print();
msg1 = msg2;
msg1.print();
msg2.print();
fldr.print();
return 0;
}
练习 13.35:
如果message的内容被改变,folders中的message内容不同步。
练习 13.38:
在处理动态分配的内存时,拷贝并交换是一种很好的方式。在Message类中,没有动态分配任何内容。因此,使用这种习惯用法没有任何意义,而且由于返回的指针,实现起来会更加复杂。
练习 13.39 && 13.40:
#ifndef STRVEC_H_
#define STRVEC_H_
#include<string>
#include<memory>
#include<initializer_list>
using namespace std;
class StrVec
{
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec(initializer_list<string>);
StrVec& operator=(const StrVec&);
~StrVec();
void push_back(const string&);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
string* begin()const { return elements; }
string* end()const { return first_free; }
string& at(size_t pos) const { return *(elements + pos); }
void reserve(size_t newcapacity);
void resize(size_t count);
void resize(size_t count, const string&);
private:
allocator<string> alloc; // 分配元素
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
void reallocate(); // 分配内存并拷贝已有元素
void alloc_n_move(size_t); // 工具函数,分配内存并移动元素
void range_initialize(const string*, const string*);
// 工具函数,拷贝控制成员所使用
pair<string*, string*> alloc_n_copy(const string* beg, const string* end); // 开辟内存并拷贝元素
void free(); // 销毁元素并释放内存
string* elements; // 指向首元素的指针
string* first_free; // 指向数组第一个空闲元素的指针
string* cap; // 指向数组尾后位置的指针
};
#endif
#include"StrVec.h"
pair<string*, string*> StrVec::alloc_n_copy(const string* beg, const string* end)
{
// 分配空间保存给定范围中的元素
auto pbeg = alloc.allocate(end - beg);
auto pend = uninitialized_copy(beg, end, pbeg);
// 返回一对pair,分别指向首元素和最后一个元素之后的位置
return pair<string*, string*>(pbeg, pend);
}
void StrVec::free()
{
if (elements)
{
for (auto p = first_free; p != elements;)
alloc.destroy(--p); // 逆序销毁元素
alloc.deallocate(elements, cap - elements); // 释放内存
}
}
void StrVec::range_initialize(const string* beg, const string* end)
{
auto newdata = alloc_n_copy(beg, end);
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::StrVec(initializer_list<string> il)
{
range_initialize(il.begin(), il.end());
}
StrVec::StrVec(const StrVec& rhs)
{
range_initialize(rhs.begin(), rhs.end());
}
StrVec& StrVec::operator=(const StrVec& rhs)
{
auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
StrVec::~StrVec()
{
free();
}
void StrVec::push_back(const string& s)
{
chk_n_alloc(); // 确保有空间容纳新元素
// 在first_free指向的元素中构造s的副本
alloc.construct(first_free++, s);
}
void StrVec::alloc_n_move(size_t newcapacity)
{
// 分配新内存
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata; // 用来保存新数组下一个空闲位置
for (auto beg = elements; beg != first_free; ++beg)
alloc.construct(dest++, std::move(*beg)); // 调用move使用string的移动构造函数
free(); // 释放旧内存空间
// 更新指针
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
void StrVec::reallocate() // 分配内存并拷贝已有元素
{
// 分配当前大小2倍的内存空间
auto newcapacity = size() ? 2 * size() : 1;
alloc_n_move(newcapacity);
}
void StrVec::reserve(size_t newcapacity)
{
if (newcapacity <= capacity())
return;
alloc_n_move(newcapacity);
}
void StrVec::resize(size_t count)
{
resize(count, string());
}
void StrVec::resize(size_t count, const string& s)
{
if (count > size())
{
if (count > capacity())
reserve(2 * count);
while (first_free != elements + count)
alloc.construct(first_free++, s);
}
else if (count < size())
{
while (first_free != elements + count)
alloc.destroy(--first_free);
}
}
练习 13.41:
因为first_free指向最后一个实际元素之后的位置,所以应该用后置递增运算依次添加元素,如果使用前置递增运算,中间会空出一个内存,这种情况是未定义的。
练习 13.42:
#ifndef TEXTQUERY_H_
#define TEXTQUERY_H_
#include<iostream>
#include<string>
#include<fstream>
#include<memory>
#include<set>
#include<map>
using namespace std;
#include"StrVec.h"
class QueryResult;
class TextQuery
{
public:
TextQuery(ifstream&);
QueryResult query(const string&)const;
private:
shared_ptr<StrVec> file;
map<string, shared_ptr<set<size_t>>> wm;
};
class QueryResult
{
friend ostream& print(ostream&, const QueryResult&);
public:
QueryResult(const string& s, shared_ptr<set<size_t>> plines, shared_ptr<StrVec> f) :
sought(s), lines(plines), file(f) { }
private:
string sought;
shared_ptr<set<size_t>> lines;
shared_ptr<StrVec> file;
};
ostream& print(ostream& os, const QueryResult& qr);
#endif
#include"TextQuery.h"
#include<sstream>
#include<algorithm>
TextQuery::TextQuery(ifstream& ifs) : file(new StrVec)
{
size_t lineNo = 0;
for (string line; getline(ifs, line); ++lineNo)
{
file->push_back(line); // 保存此行文本
istringstream line_iss(line);
for (string word; line_iss >> word;)
{
// 避免读入标点符号
auto punct_pos = find_if(word.begin(), word.end(), ispunct);
if (punct_pos != word.end())
word = string(word.begin(), punct_pos);
// 如果单词不在wm中,以之为下标在wm中添加一项
auto& lines = wm[word];
if (!lines) // 第一次遇到这个单词时,此指针为空
lines.reset(new set<size_t>);
lines->insert(lineNo);
}
}
}
QueryResult TextQuery::query(const string& sought)const
{
// 如果未找到sought, 我们将返回指向此set的指针
static shared_ptr<set<size_t>> nodata(new set<size_t>);
auto loc = wm.find(sought);
if (loc != wm.end())
return QueryResult(sought, loc->second, file);
else
return QueryResult(sought, nodata, file);
}
// 打印结果
ostream& print(ostream& os, const QueryResult& qr)
{
os << qr.sought << " occurs " << qr.lines->size()
<< (qr.lines->size() > 1 ? " times" : " time") << endl;
// 打印单词出现的每一行
for (auto line : *qr.lines)
os << "\t(line " << line + 1 << ") " << qr.file->at(line) << endl;
return os;
}
#include"TextQuery.h"
#include<iostream>
void runQueries(ifstream& infile)
{
TextQuery tq(infile); // 保存文件并建立查询map
while (true)
{
cout << "enter word to look for, or \"q\" to quit: ";
string s;
if (cin >> s && s != "q")
print(cout, tq.query(s)) << endl;
else
break;
}
}
int main()
{
ifstream file("storyDataFile.txt");
runQueries(file);
}
练习 13.43:
for_each(elements, first_free, [this](string& s) {alloc.destroy(&s); });
练习 13.44:
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;
class String
{
friend ostream& print(ostream& os, const String& s);
public:
String(): elements(nullptr), end(nullptr){}
String(const char*);
String(const String&);
String& operator=(const String&);
~String();
size_t size()const { return end - elements; }
private:
pair<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
allocator<char> alloc;
char* elements;
char* end;
};
pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
auto str = alloc.allocate(e - b);
return { str, std::uninitialized_copy(b, e, str) };
}
void String::free()
{
if (elements)
{
for_each(elements, end, [this](char& c) { alloc.destroy(&c); });
alloc.deallocate(elements, end - elements);
}
}
void String::range_initializer(const char* b, const char* e)
{
auto newStr = alloc_n_copy(b, e);
elements = newStr.first;
end = newStr.second;
}
String::String(const char* s)
{
char* s1 = const_cast<char*>(s);
while (*s1)
++s1;
range_initializer(s, s1);
}
String::String(const String& rhs)
{
range_initializer(rhs.elements, rhs.end);
}
String& String::operator=(const String& rhs)
{
auto newStr = alloc_n_copy(rhs.elements, rhs.end);
free();
elements = newStr.first;
end = newStr.second;
return *this;
}
String::~String() { free(); }
ostream& print(ostream& os, const String& s)
{
for (auto beg = s.elements; beg != s.end; ++beg)
os << *beg;
return os;
}
练习 13.45:
- 左值引用:可以绑定到左值的引用。还可以将const的左值引用绑定到一个右值上。
- 右值引用: 必须绑定到右值的引用,指向将被销毁的对象。
可以将右值引用绑定到要求转换的表达式、字面常量或是返回右值的表达式,但不能直接将一个右值引用绑定到一个左值。
练习 13.46:
int f();
vector<int> vi(100);
int&& r1 = f();
int& r2 = vi[0];
int& r3 = r1;
int&& r4 = vi[0] * f();
练习 13.47:
#ifndef STRING_HPP_
#define STRING_HPP_
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;
class String
{
friend ostream& print(ostream& os, const String& s);
public:
String() : elements(nullptr), end(nullptr) {}
String(const char*);
String(const String&);
String& operator=(const String&);
~String();
size_t size()const { return end - elements; }
private:
pair<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
allocator<char> alloc;
char* elements;
char* end;
};
pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
auto str = alloc.allocate(e - b);
return { str, std::uninitialized_copy(b, e, str) };
}
void String::free()
{
if (elements)
{
for_each(elements, end, [this](char& c) { alloc.destroy(&c); });
alloc.deallocate(elements, end - elements);
}
}
void String::range_initializer(const char* b, const char* e)
{
auto newStr = alloc_n_copy(b, e);
elements = newStr.first;
end = newStr.second;
}
String::String(const char* s)
{
char* s1 = const_cast<char*>(s);
while (*s1)
++s1;
range_initializer(s, s1);
}
String::String(const String& rhs)
{
range_initializer(rhs.elements, rhs.end);
cout << "Copy construction" << endl;
}
String& String::operator=(const String& rhs)
{
auto newStr = alloc_n_copy(rhs.elements, rhs.end);
free();
elements = newStr.first;
end = newStr.second;
cout << "Copy assignment" << endl;
return *this;
}
String::~String() { free(); }
ostream& print(ostream& os, const String& s)
{
for (auto beg = s.elements; beg != s.end; ++beg)
os << *beg;
return os;
}
#endif
练习 13.48:
#include"String.hpp"
#include<iostream>
#include<vector>
int main()
{
const char* chs = "Hello Word";
String s1("cpp");
String s2(chs);
String s3(s1);
String s4 = s2;
vector<String> StrVec;
StrVec.push_back(s1);
StrVec.push_back(s2);
StrVec.push_back(s3);
StrVec.push_back(s4);
for (const auto& s : StrVec)
print(cout, s) << endl;
}
练习 13.49:
#include<string>
#include<memory>
#include<initializer_list>
#include<algorithm>
using namespace std;
class StrVec
{
public:
StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {}
StrVec(const StrVec&);
StrVec(initializer_list<string>);
StrVec& operator=(const StrVec&);
StrVec(StrVec&&)noexcept;
StrVec& operator=(StrVec&&)noexcept;
~StrVec();
void push_back(const string&);
size_t size()const { return first_free - elements; }
size_t capacity()const { return cap - elements; }
string* begin()const { return elements; }
string* end()const { return first_free; }
string& at(size_t pos) const { return *(elements + pos); }
void reserve(size_t newcapacity);
void resize(size_t count);
void resize(size_t count, const string&);
private:
allocator<string> alloc; // 分配元素
void chk_n_alloc()
{
if (size() == capacity())
reallocate();
}
void reallocate(); // 分配内存并拷贝已有元素
void alloc_n_move(size_t); // 工具函数,分配内存并移动元素
void range_initialize(const string*, const string*);
// 工具函数,拷贝控制成员所使用
pair<string*, string*> alloc_n_copy(const string* beg, const string* end); // 开辟内存并拷贝元素
void free(); // 销毁元素并释放内存
string* elements; // 指向首元素的指针
string* first_free; // 指向数组第一个空闲元素的指针
string* cap; // 指向数组尾后位置的指针
};
pair<string*, string*> StrVec::alloc_n_copy(const string* beg, const string* end)
{
// 分配空间保存给定范围中的元素
auto pbeg = alloc.allocate(end - beg);
auto pend = uninitialized_copy(beg, end, pbeg);
// 返回一对pair,分别指向首元素和最后一个元素之后的位置
return pair<string*, string*>(pbeg, pend);
}
void StrVec::free()
{
if (elements)
{
for_each(elements, first_free, [this](string& s) {alloc.destroy(&s); });
alloc.deallocate(elements, cap - elements); // 释放内存
}
}
void StrVec::range_initialize(const string* beg, const string* end)
{
auto newdata = alloc_n_copy(beg, end);
elements = newdata.first;
first_free = cap = newdata.second;
}
StrVec::StrVec(initializer_list<string> il)
{
range_initialize(il.begin(), il.end());
}
StrVec::StrVec(const StrVec& rhs)
{
range_initialize(rhs.begin(), rhs.end());
}
StrVec& StrVec::operator=(const StrVec& rhs)
{
auto newdata = alloc_n_copy(rhs.begin(), rhs.end());
free();
elements = newdata.first;
first_free = cap = newdata.second;
return *this;
}
StrVec::~StrVec()
{
free();
}
void StrVec::push_back(const string& s)
{
chk_n_alloc(); // 确保有空间容纳新元素
// 在first_free指向的元素中构造s的副本
alloc.construct(first_free++, s);
}
void StrVec::alloc_n_move(size_t newcapacity)
{
// 分配新内存
auto newdata = alloc.allocate(newcapacity);
auto dest = newdata; // 用来保存新数组下一个空闲位置
for (auto beg = elements; beg != first_free; ++beg)
alloc.construct(dest++, std::move(*beg)); // 调用move使用string的移动构造函数
free(); // 释放旧内存空间
// 更新指针
elements = newdata;
first_free = dest;
cap = elements + newcapacity;
}
void StrVec::reallocate() // 分配内存并拷贝已有元素
{
// 分配当前大小2倍的内存空间
auto newcapacity = size() ? 2 * size() : 1;
alloc_n_move(newcapacity);
}
void StrVec::reserve(size_t newcapacity)
{
if (newcapacity <= capacity())
return;
alloc_n_move(newcapacity);
}
void StrVec::resize(size_t count)
{
resize(count, string());
}
void StrVec::resize(size_t count, const string& s)
{
if (count > size())
{
if (count > capacity())
reserve(2 * count);
while (first_free != elements + count)
alloc.construct(first_free++, s);
}
else if (count < size())
{
while (first_free != elements + count)
alloc.destroy(--first_free);
}
}
StrVec::StrVec(StrVec&& rhs)noexcept
:elements(rhs.elements), first_free(rhs.first_free), cap(rhs.cap)
{
// 令rhs进入这样的状态--对其运行析构函数是安全的
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
StrVec& StrVec::operator=(StrVec&& rhs)noexcept
{
// 直接检查自赋值
if (this != &rhs)
{
free(); // 释放已有元素
elements = rhs.elements; // 从rhs接管资源
first_free = rhs.first_free;
cap = rhs.cap;
// 将rhs置于可析构状态
rhs.elements = rhs.first_free = rhs.cap = nullptr;
}
return *this;
}
#ifndef STRING_H_
#define STRING_H_
#include<iostream>
#include<memory>
#include<algorithm>
using namespace std;
class String
{
friend ostream& print(ostream& os, const String& s);
public:
String() : elements(nullptr), end(nullptr) {}
String(const char*);
String(const String&);
String& operator=(const String&);
String(String&&)noexcept;
String& operator=(String&&)noexcept;
~String();
size_t size()const { return end - elements; }
private:
pair<char*, char*> alloc_n_copy(const char*, const char*);
void range_initializer(const char*, const char*);
void free();
allocator<char> alloc;
char* elements;
char* end;
};
pair<char*, char*> String::alloc_n_copy(const char* b, const char* e)
{
auto str = alloc.allocate(e - b);
return { str, std::uninitialized_copy(b, e, str) };
}
void String::free()
{
if (elements)
{
for_each(elements, end, [this](char& c) { alloc.destroy(&c); });
alloc.deallocate(elements, end - elements);
}
}
void String::range_initializer(const char* b, const char* e)
{
auto newStr = alloc_n_copy(b, e);
elements = newStr.first;
end = newStr.second;
}
String::String(const char* s)
{
char* s1 = const_cast<char*>(s);
while (*s1)
++s1;
range_initializer(s, s1);
}
String::String(const String& rhs)
{
range_initializer(rhs.elements, rhs.end);
cout << "Copy construction" << endl;
}
String& String::operator=(const String& rhs)
{
auto newStr = alloc_n_copy(rhs.elements, rhs.end);
free();
elements = newStr.first;
end = newStr.second;
cout << "Copy assignment" << endl;
return *this;
}
String::String(String&& rhs)noexcept: elements(rhs.elements), end(rhs.end)
{
rhs.elements = rhs.end = nullptr;
}
String& String::operator=(String&& rhs)noexcept
{
if (this != &rhs)
{
free();
elements = rhs.elements;
end = rhs.end;
rhs.elements = rhs.end = nullptr;
}
return *this;
}
String::~String() { free(); }
ostream& print(ostream& os, const String& s)
{
for (auto beg = s.elements; beg != s.end; ++beg)
os << *beg;
return os;
}
#endif
#include<iostream>
#include<string>
#include<set>
#include<algorithm>
using namespace std;
class Folder;
class Message
{
friend class Folder;
friend void swap(Message& lhs, Message& rhs);
public:
Message(const string& str = "") : contents(str) {}
Message(const Message&);
Message& operator=(const Message&);
Message(Message&&);
Message& operator=(Message&&);
~Message();
// 从给定Folder集合中添加/删除本Message
void save(Folder&);
void remove(Folder&);
void print() { cout << contents << endl; }
private:
string contents; // 实际消息文本
set<Folder*> folders; // 包含本message的folder
// 将本Message添加到指向参数的Folder中
void add_to_Folders(const Message&);
// 从folders中的每个folder中删除本Message
void remove_from_Folders();
void move_Folders(Message*);
void addFldr(Folder* f) { this->folders.insert(f); }
void remFldr(Folder* f) { this->folders.erase(f); }
};
class Folder
{
friend class Message;
friend void swap(Folder& lhs, Folder& rhs);
public:
Folder() = default;
Folder(const Folder&);
Folder& operator=(const Folder&);
~Folder();
void print()
{
for (auto m : this->msgs)
cout << m->contents << " ";
cout << endl;
}
private:
set<Message*> msgs;
void add_to_Message(const Folder&);
void remove_from_Message();
void addMsg(Message* m) { msgs.insert(m); }
void remMsg(Message* m) { msgs.erase(m); }
};
// Message类的成员函数
// 将本Message添加到指向参数的Folder中
void Message::add_to_Folders(const Message& m)
{
for (auto f : m.folders) // 对每个包含m的folder
f->addMsg(this); // 向该folder添加一个指向本Message的指针
}
// 拷贝构造
Message::Message(const Message& rhs) : contents(rhs.contents), folders(rhs.folders)
{
this->add_to_Folders(rhs);
}
// 从对应的folders中删除本Message
void Message::remove_from_Folders()
{
for (auto f : this->folders)// 对于folders中每个指针
f->remMsg(this); // 从该folder中删除本message
}
// 析构
Message::~Message()
{
this->remove_from_Folders();
}
// 拷贝赋值
Message& Message::operator=(const Message& rhs)
{
this->remove_from_Folders();
this->contents = rhs.contents;
this->folders = rhs.folders;
this->add_to_Folders(rhs); // 将本Message添加到那些Folder中
return *this;
}
void Message::move_Folders(Message* m)
{
folders = std::move(m->folders); // 接管m的folders
for (auto f : folders)
{
f->remMsg(m); // 从Folder中删除旧Message
f->addMsg(this); // 将本Message添加到Folder中
}
m->folders.clear(); // 确保销毁m是无害的
}
Message::Message(Message&& rhs): contents(std::move(rhs.contents))
{
move_Folders(&rhs);
}
Message& Message::operator=(Message&& rhs)
{
if (this != &rhs)
{
remove_from_Folders();
contents = std::move(rhs.contents);
move_Folders(&rhs);
}
return *this;
}
// 从给定Folder集合中添加本Message
void Message::save(Folder& f)
{
this->folders.insert(&f);
f.addMsg(this);
}
// 从给定Folder集合中删除本Message
void Message::remove(Folder& f)
{
this->folders.erase(&f);
f.remMsg(this);
}
void swap(Message& lhs, Message& rhs)
{
// 将每个消息的指针从它(旧)所在Folder中删除
lhs.remove_from_Folders();
rhs.remove_from_Folders();
// 交换contents和Folder指针
swap(lhs.contents, rhs.contents);
swap(lhs.folders, rhs.folders);
// 将每个Message的指针添加到它的(新)Folder中
lhs.add_to_Folders(lhs);
rhs.add_to_Folders(rhs);
}
// Folder类的成员函数
void Folder::add_to_Message(const Folder& f)
{
for (auto m : f.msgs)
m->addFldr(this);
}
// 拷贝构造
Folder::Folder(const Folder& rhs) : msgs(rhs.msgs)
{
this->add_to_Message(rhs);
}
void Folder::remove_from_Message()
{
for (auto m : this->msgs)
m->remFldr(this);
}
// 析构
Folder::~Folder()
{
this->remove_from_Message();
}
// 拷贝赋值
Folder& Folder::operator=(const Folder& rhs)
{
this->remove_from_Message();
this->msgs = rhs.msgs;
this->add_to_Message(rhs);
return *this;
}
void swap(Folder& lhs, Folder& rhs)
{
lhs.remove_from_Message();
rhs.remove_from_Message();
swap(lhs.msgs, rhs.msgs);
lhs.add_to_Message(lhs);
rhs.add_to_Message(rhs);
}
练习 13.50:
#include"String.h"
#include<iostream>
#include<vector>
int main()
{
const char* chs = "Hello Word";
String s1("cpp");
String s2(chs);
String s3(s1); // Copy construction
String s4;
s4 = s2; // Copy assignment
vector<String> StrVec;
StrVec.push_back(s1); // Copy construction
StrVec.push_back(s2); // Copy construction + Move construction
StrVec.push_back(s3); // Copy construction + 2 * Move construction
StrVec.push_back(s4); // Copy construction + 3 * Move construction
for (const auto& s : StrVec)
print(cout, s) << endl;
}
练习 13.51:
unique_ptr<int> clone(int p) {
return unique_ptr<int>(new int(p));
}
调用clone的结果是右值,因此它使用移动赋值运算符而不是拷贝赋值运算符。因此,它是合法的,可以正确工作。
练习 13.52:
HasPtr& operator=(HasPtr rhs)
{
swap(*this, rhs);
return *this;
}
rhs是一个非引用参数,这意味着此参数是拷贝初始化的。依赖于实参的类型,拷贝初始化要么使用拷贝构造函数要么使用移动构造函数——左值被拷贝,右值被移动。
hp = hp2; // hp2是一个左值; hp2通过拷贝构造函数来拷贝
hp = std::move(hp2) // 移动构造函数移动hp2
练习 13.53:
HasPtr的赋值运算符调用拷贝构造(移动构造)和swap,而它的拷贝赋值运算符调用拷贝构造,移动赋值运算符调用移动构造,所以HasPtr的赋值运算符底层效率并不理想。
#include<iostream>
#include<string>
using namespace std;
class HasPtr
{
friend ostream& print(ostream& os, HasPtr& hp);
friend void swap(HasPtr& lhs, HasPtr& rhs);
public:
HasPtr(const string& s = string()) : ps(new string(s)), i(0) {}
HasPtr(const HasPtr& hp) : ps(new string(*hp.ps)), i(hp.i)
{
cout << "copy constructor" << endl;
}
HasPtr(HasPtr&& hp)noexcept : ps(hp.ps), i(hp.i)
{
hp.ps = nullptr;
cout << "move constructor" << endl;
}
// 赋值运算符既是移动赋值运算符,也是拷贝赋值运算符
HasPtr& operator=(HasPtr rhs)
{
swap(*this, rhs);
return *this;
}
// 拷贝赋值运算符
//HasPtr& operator=(const HasPtr& rhs)
//{
// auto newp = new string(*rhs.ps);
// delete ps;
// ps = newp;
// i = rhs.i;
// cout << "copy assignment" << endl;
// return *this;
//}
// 移动赋值运算符
//HasPtr& operator=(HasPtr&& rhs)noexcept
//{
// if (this != &rhs)
// {
// delete ps;
// ps = rhs.ps;
// i = rhs.i;
// rhs.ps = nullptr;
// cout << "move assignment" << endl;
// }
// return *this;
//}
~HasPtr() { delete ps; }
private:
string* ps;
int i;
};
ostream& print(ostream& os, HasPtr& hp)
{
os << *hp.ps << " " << hp.i;
return os;
}
inline
void swap(HasPtr& lhs, HasPtr& rhs)
{
swap(lhs.ps, rhs.ps);
swap(lhs.i, rhs.i);
cout << "use swap(HasPtr& lhs, HasPtr& rhs)" << endl;
}
int main()
{
HasPtr hp1("Cpp");
HasPtr hp2("Java");
print(cout, hp1) << endl;
print(cout, hp2) << endl;
hp1 = hp2; // 调用copy assignment + swap
print(cout, hp1) << endl;
hp1 = std::move(hp2); // 调用move assignment + swap
print(cout, hp1) << endl;
return 0;
}
练习 13.54:
// 有多个"="运算符与这些操作数匹配:
// HasPtr& operator=(HasPtr rhs) HasPtr& operator=(HasPtr&& rhs)
hp1 = std::move(hp2);
练习 13.55:
void push_back(const string&& t) { data->push_back(std::move(t)); }
练习 13.56:
ret是一个左值,返回他的sorted函数,代码将陷入递归,并导致致命的堆栈溢出,程序异常终止。
练习 13.57:
调用右值版本的sorted函数,程序正常运行。
练习 13.58:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
class Foo
{
public:
Foo sorted()&&;
Foo sorted()const&;
private:
vector<int> data;
};
// 本对象为右值,因此可以原址排序
Foo Foo::sorted()&&
{
sort(data.begin(), data.end());
cout << "sorted()&&" << endl;
return *this;
}
// 本对象是const或是一个左值,那种情况我们都不能对其进行原址排序
Foo Foo::sorted()const&
{
/*Foo ret(*this);
sort(ret.data.begin(), ret.data.end());
return ret;*/
cout << "sorted()const&" << endl;
/*Foo ret(*this);
return ret.sorted();*/
return Foo(*this).sorted();
}
int main()
{
Foo().sorted();
Foo f;
f.sorted();
return 0;
}