第13章 拷贝控制

13.26

class HasPtr {
public:
	HasPtr() = default;
	HasPtr(const string& s = string()) :
		ps(new string(s)), i(0) {}
	HasPtr(const HasPtr& p) :
		ps(new string(*p.ps)), i(p.i) {}

	HasPtr& operator=(const HasPtr& rhs){
		auto newp = new string(*rhs.ps);
		delete ps;
		ps = newp;
		i = rhs.i;
		return *this;
	}

	~HasPtr() { delete ps; }
private:
	string* ps;
	int i;
};

13.27

class HasPtr {
public:
	HasPtr(const string& s = string()) :
		ps(new string(s)), i(0), use(new size_t(1)) {}
	HasPtr(const HasPtr& p) :
		ps(p.ps), i(p.i), use(p.use) {
		++* use;
	}

	HasPtr& operator=(const HasPtr& rhs) {
		++* use;
		if (-- * use == 0) {
			delete ps;
			delete use;
		}
		ps = rhs.ps;
		i = rhs.i;
		use = rhs.use;
		return *this;
	}

	~HasPtr() {
		if (-- * use == 0) {
			delete ps;
			delete use;
		}
	}
private:
	string* ps;
	int i;
	size_t* use;	//引用计数
};

13.28

#include<iostream>
#include<vector>
#include<string>

using namespace std;

class TreeNode {
public:
	TreeNode() :
		value(), count(0), left(nullptr), right(nullptr) {}
	TreeNode(const string& s, int c, TreeNode& l, TreeNode& r) :
		value(s), count(c), left(new TreeNode(l)), right(new TreeNode(r)) {}
	TreeNode(const TreeNode& t) :
		value(t.value), count(t.count) {
		if (t.left != nullptr)
			left = new TreeNode(*t.left);
		else
			left = nullptr;
		if (t.right != nullptr)
			right = new TreeNode(*t.right);
		else
			right = nullptr;
	}

	TreeNode& operator=(const TreeNode& t) {
		value = t.value;
		count = t.count;
		if (t.left != nullptr)
			left = new TreeNode(*t.left);
		else
			left = nullptr;
		if (t.right != nullptr)
			right = new TreeNode(*t.right);
		else
			right = nullptr;
		return *this;
	}

	~TreeNode() {
		if (left != nullptr)
			delete left;
		if (right != nullptr)
			delete right;
	}
private:
	string value;
	int count;
	TreeNode* left;
	TreeNode* right;
};

class BinStrTree {
public:
	BinStrTree() :
		root(new TreeNode()) {}
	BinStrTree(const TreeNode& t) :
		root(new TreeNode(t)) {}
	BinStrTree(const BinStrTree& bt) :
		root(new TreeNode(*bt.root)) {}

	BinStrTree& operator=(const BinStrTree& bt) {
		auto newt = new BinStrTree(bt);
		delete root;
		root = newt->root;
		return *this;
	}

	~BinStrTree() { delete root; }
private:
	TreeNode* root;
};

int main()
{
	TreeNode n1, n2, n4, n5;
	TreeNode n6("hello", 3, n4, n5);
	n2 = n6;
	TreeNode n3(n6);
	BinStrTree b1;
	BinStrTree b2(n6);
	b1 = b2;
	BinStrTree b3(b1);
	system("pause");
	return 0;
}

13.27

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>

using namespace std;

static int n = 0;

class HasPtr {
	friend void swap(HasPtr&, HasPtr&);
	friend bool operator<(HasPtr& lhs, HasPtr& rhs);
public:
	HasPtr(const string& s = string()) :
		ps(new string(s)), i(0) {}
	HasPtr(const HasPtr& p) :
		ps(new string(*p.ps)), i(p.i) {}
	HasPtr& operator=(HasPtr rhs) {
		swap(*this, rhs);
		return *this;
	}
	void print() { cout << *ps << endl; }
	~HasPtr() { delete ps; }
private:
	string* ps;
	int i;
};

inline
void swap(HasPtr& lhs, HasPtr& rhs) {
	using std::swap;
	swap(lhs.ps, rhs.ps);
	swap(lhs.i, rhs.i);
	n++;
	cout << "swap" << endl;
}

bool operator<(HasPtr& lhs, HasPtr& rhs) {
	return *lhs.ps < *rhs.ps;
}

int main()
{
	vector<HasPtr> vec{ (string)"sfdd" };
	for (int i = 0; i < 1000; ++i)
		vec.push_back(string("dzx"));
	std::sort(vec.begin(), vec.end());
	cout << n << endl;
	//for (auto m : vec)
	//	m.print();
	return 0;
}

元素数目过少时sort使用插入排序,未使用swap,在VS中临界值似乎为32。
当元素数目变大时,sort会使用快速排序,此时使用自定义版本的swap,当剩余无序元素小于临界值后继续使用插入排序。

注意添加元素时不能让所有元素全部相等,不然编译器就不会使用快速排序,也就不会调用swap。(坑了我好久…)

13.37

h

#ifndef	TEST_H
#define	TEST_H

#include <set>
using namespace std;

class Folder;
class Message {
	friend class Folder;
	friend void swap(Message&, Message&);
public:
	explicit Message(const string& str = "") :
		contents(str) {}
	Message(const Message&);
	Message& operator=(const Message&);
	~Message();

	void save(Folder&);
	void remove(Folder&);
	void addfol(Folder*);
	void remfol(Folder*);
	void print();

	void test();
private:
	string contents;
	set<Folder*> folders;

	void add_to_Folders(const Message&);
	void remove_from_Folders();
};

class Folder {
	friend class Message;
	friend void swap(Message&, Message&);
public:
	Folder() = default;
	Folder(const Folder& f);
	Folder& operator=(const Folder&);
	~Folder();

	void addMsg(Message*);
	void remMsg(Message*);
	void print();

private:
	set<Message*> messages;

	void add_to_Messages(const Folder&);
	void remove_from_Messages();
};

#endif

cpp

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;

//函数定义
void swap(Message& lhs, Message& rhs)
{
	using std::swap;
	//移除保存双方的Folder的记录
	for (auto f : lhs.folders)
		f->remMsg(&lhs);
	for (auto f : lhs.folders)
		f->remMsg(&rhs);

	swap(lhs.folders, rhs.folders);
	swap(lhs.contents, rhs.contents);

	for (auto f : lhs.folders)
		f->addMsg(&lhs);
	for (auto f : rhs.folders)
		f->addMsg(&rhs);
}

void Folder::print()
{
	cout << "Messages:";
	for (auto m : messages)
	{
		cout << " " << m->contents;
	}
	cout << endl;
}

void Message::print()
{
	cout << "Save in " << folders.size() << " Folders" << endl;
}

void Message::test()
{
	Folder f1;
	folders.insert(&f1);
}

//Message定义
Message::Message(const Message& m) :
	contents(m.contents), folders(m.folders)
{
	add_to_Folders(m);
}

Message& Message::operator=(const Message& rhs)
{
	remove_from_Folders();
	contents = rhs.contents;
	folders = rhs.folders;
	add_to_Folders(rhs);
	return *this;
}

Message::~Message()
{
	remove_from_Folders();
}

void Message::save(Folder& f)	//保存到指定Folder中
{
	addfol(&f);	//更新自身的Folders目录
	f.addMsg(this);	//向Folder中添加自身
}

void Message::remove(Folder& f)	//从指定Folder中移除
{
	remfol(&f);
	f.remMsg(this);
}

void Message::addfol(Folder* f)
{
	folders.insert(f);
}

void Message::remfol(Folder* f)
{
	folders.erase(f);
}

void Message::add_to_Folders(const Message& m)	//拷贝构造以及拷贝赋值中均需此操作
{
	for (auto f : m.folders)	//对于每个保存m的Folder
		f->addMsg(this);	//向其中添加Message自身
}

void Message::remove_from_Folders()	//清空保存自身的Folders
{
	for (auto f : folders)
		f->remMsg(this);
}

//Folder定义
Folder::Folder(const Folder& f) :
	messages(f.messages)
{
	add_to_Messages(f);
}

Folder& Folder::operator=(const Folder& f)
{
	remove_from_Messages();
	messages = f.messages;
	add_to_Messages(f);
	return *this;
}

Folder::~Folder()
{
	remove_from_Messages();
}

void Folder::addMsg(Message* m)	//添加单个Message元素
{
	messages.insert(m);
}

void Folder::remMsg(Message* m)	//同上
{
	messages.erase(m);
}

void Folder::add_to_Messages(const Folder& f)
{
	for (auto m : f.messages)	//对于目录中的每一条Message进行单次操作
		m->addfol(this);	//此处切勿使用save!因为会被save中的f.addMsg(this)循环调用自身
	//下方remove同理
}

void Folder::remove_from_Messages()	//清空目录中保存的Message
{
	for (auto m : messages)
		m->remfol(this);
}

int main()
{
	Message m1("Hello");
	Message m2("World");
	Folder f1;
	m1.save(f1);
	m2.save(f1);
	f1.print();
	m1.print();
	return 0;
}

13.39 & 13.41

StrVec.h

#include<iostream>
#include<string>
#include<memory>
#include<initializer_list>
using namespace std;

class StrVec {
public:
	StrVec() :
		elements(nullptr), first_free(nullptr), cap(nullptr) {}
	StrVec(const initializer_list<string>&);
	StrVec(const StrVec&);
	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; }
	void reserve(size_t sz);
	void resize(size_t, const string& = string());	//声明不要忘记设置缺省值
	void print();
private:
	static allocator<string> alloc;
	void chk_n_alloc() {
		if (size() == capacity()) reallocate();
	}
	pair<string*, string*> alloc_n_copy
	(const string*, const string*);
	void free();
	void reallocate();
	string* elements;
	string* first_free;
	string* cap;
};

StrVec.cpp

#include"test.h"

allocator<string> StrVec::alloc;

StrVec::StrVec(const initializer_list<string>& lst)
{
	elements = alloc.allocate(lst.end() - lst.begin());
	cap = first_free = uninitialized_copy(lst.begin(), lst.end(), 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::operator=(const StrVec& s)
{
	auto newdata = alloc_n_copy(s.begin(), s.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();
	alloc.construct(first_free++, s);
}

void StrVec::reserve(size_t sz)
{
	if (sz > capacity()) {
		auto newdata = alloc.allocate(sz);
		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 + sz;
	}
}

void StrVec::resize(size_t n, const string& s)
{
	if (n == size())
		return;
	if (n < capacity()) {
		if (n > size())
			for (int i = 0; i < n; ++i)
				alloc.construct(first_free++, s);
		else
			for (auto p = first_free; p != elements + n; )
				alloc.destroy(--p);
		first_free = elements + n;
	}
	else {
		this->reserve(n + size());
		for (int i = 0; i < n; ++i)
			alloc.construct(first_free++, s);
	}
}

void StrVec::print()
{
	for (auto i = elements; i != first_free; ++i)
		cout << *i << " ";
}

pair<string*, string*>
StrVec::alloc_n_copy(const string* b, const 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; )
		//	alloc.destroy(--p);

		for_each(elements, first_free, [&](string p) {
			alloc.destroy(&p);
			});

		alloc.deallocate(elements, cap - elements);
	}
}

void StrVec::reallocate()
{
	auto newcapacity = size() ? 2 * size() : 1;
	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;
}

main.cpp

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;

void test(StrVec& s) {
	cout << endl;
	s.print();
	cout << endl;
	cout << "\tCapacity " << s.capacity() << "\tSize " << s.size() << endl;
}

int main()
{
	initializer_list<string> list{ "First", "test", };
	StrVec s1, s2(list), s3(s2), s4 = s3;
	s1 = s2;

	test(s1);

	s2.push_back("Push_back Test");
	test(s2);

	s3.reserve(25);
	test(s3);

	s4.resize(8, "Resize");
	test(s4);

	s4.resize(3);
	test(s4);

	s4.resize(1, "Resize");
	test(s4);

	return 0;
}

在这里插入图片描述

13.44

String.h

#include<memory>
#include<algorithm>
using namespace std;

class String {
	friend ostream& operator<<(ostream&, const String&);
public:
	String() : element(nullptr), first_free(nullptr) {}
	String(const char* s) {
		size_t sz = strlen(s);
		auto newdata = alloc.allocate(sz);
		auto dest = newdata;
		for (unsigned int i = 0; i != sz; ++i)
			alloc.construct(dest++, s[i]);
		element = newdata;
		first_free = dest;
	}
private:
	static allocator<char> alloc;
	char* element;
	char* first_free;
};

main.cpp

#include<iostream>
#include<vector>
#include<string>
#include<algorithm>
#include"test.h"
using namespace std;

ostream& operator<<(ostream& os, const String& s) {
	auto c = s.element;
	while (c != s.first_free)
		os << *c++;
	return os;
}

int main()
{
	String s1("hello");
	cout << s1 << endl;
	return 0;
}

13.47

h

#include <iostream>
#include <string>
#include <utility>
#include <memory>
#include <algorithm>
using namespace std;

class String {
	friend ostream& operator<<(ostream&, const String&);
public:
	String() : element(nullptr), first_free(nullptr) {}
	String(const char* s) {
		size_t sz = strlen(s);
		auto newdata = alloc.allocate(sz);
		auto dest = newdata;
		for (unsigned int i = 0; i != sz; ++i)
			alloc.construct(dest++, s[i]);
		element = newdata;
		first_free = dest;
	}

	String(const String& s) {
		size_t sz = s.size();
		auto data = alloc.allocate(sz);
		element = data;
		first_free = uninitialized_copy(s.element, s.first_free, data);
		cout << "Copy construct" << endl;
	}

	String& operator=(const String& s) {
		size_t sz = s.size();
		auto data = alloc.allocate(sz);
		element = data;
		first_free = uninitialized_copy(s.element, s.first_free, data);
		cout << "Copy assignment" << endl;
		return *this;
	}

	size_t size() const { return first_free - element; }

	~String() {
		if (size())
		{
			for (auto p = first_free; p != element;)
				alloc.destroy(--p);
			alloc.deallocate(element, first_free - element);
		}
	}
private:
	static allocator<char> alloc;
	char* element;
	char* first_free;
};

cpp

#include <iostream>
#include <string>
#include <utility>
#include <memory>
#include <algorithm>
#include <vector>
#include"test.h"
using namespace std;

ostream& operator<<(ostream& os, const String& s) {
	auto c = s.element;
	while (c != s.first_free)
		os << *c++;
	return os;
}

int main()
{
	String s1("Hello world!");
	String s2(s1);
	String s3;
	s3 = s2;

	cout << endl;
	cout << s2 << " " << s2.size() << endl;
	cout << s3 << " " << s3.size() << endl;
	cout << endl;

	vector<String> vec;
	cout << endl;
	//vec.reserve(10);
	for (int i = 0; i < 3; ++i) {
		vec.push_back("hello");
		cout << endl;
	}
	return 0;
}

程序运行结果

默认初始化的vector每次调用push_back的时候,都会重新扩容,这将导致拷贝的次数将在当前添加的元素的基础上将原来容器中所有的元素再次全部重新拷贝一遍。
使用reserve提前声明预先分配空间的大小,可以有效减少拷贝的次数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值