C ++ Primer Chapter XIII 13.2 copy control and resource management practice and summary

13.2 copy control and resource management

Exercise

13.22

This exercise is the wrong model, the correct exercise demonstration in 13.23 in

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

	};
	//列表初始化只能在构造函数中使用
	HasPtr& operator=(const HasPtr& p) {

		ps = new string(*p.ps);
		i = p.i;
	};
	~HasPtr() {
		delete ps;
	}
private:
	std::string *ps;
	int i;
};

13.2.1 class acts like value

Want to conduct classes defined as a value, it must at the time of the assignment copies data between objects and object members are independent of each other.

For contains a built-pointer data members of the class you want to achieve class value behavior.
When pointing copy assignment operator needs to be considered at this time assignment operator copies of such integrated construction and destructor functions, on the one hand needs to be built-in pointer points to an object destruction, on the one hand needs to assign a value.

The safest wording is: First, the pointer parameter data members of the object pointed to copy, create a temporary variable.

Then delete this object pointer points to an object.

Finally, the temporary object is assigned to a pointer.

Do not delete the first pointer, because if the incoming object and the left operand is an object, first delete, then call dereference, will produce undefined behavior.

Exercise

13.23

Obviously, I write a lot of code and code gaps on the book. Problems on the overloaded assignment operator.

First of all I do not consider the assignment, ps original point of the object being removed.
So, I wrote this version:

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

In the VS2017, not overloaded assignment operator returns the value no given. .

The above code there is another problem, if the object is on the right side of the assignment operator and the operator of the left operand is an object, delete ps. * Pp will lead to undefined behavior.

Therefore, the following version is a correct version. First, this object to be destroyed to save data members with the same member of the temporary variable p.

Then delete objects need to be destroyed, and then assign the value of the temporary variable data members.

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

Destructor are not defined, it will cause a memory leak

Not defined copy constructor will cause, when re-initialization copying data members ps two objects point to the same object. If an object is destroyed, ps another object points to a space to be recovered.

13.25

If you need to continue to use shared_ptr class values ​​but also become StrBlob version.

Then the copy constructor, as required

std::shared_ptr<vector<string>> data;

Make_shared data members to use to create objects.

In the assignment operator copies, the prior does not require removing the object pointed to, directly call make_shared () can be, because the internal smart pointer with a reference count, the current pointer is assigned a new value, the reference count of the object past -1 If 0 is released and destroy the object.

Because smart pointer object, the object can maintain a self-preserved, so no destructors.

13.26
class StrBlobPtr;
class ConstStrBlobPtr;
class StrBlob {
	friend class StrBlobPtr;
	friend class ConstStrBlobPtr;
public:
	using size_type = vector<string>::size_type;
	StrBlob();
	StrBlob(std::initializer_list<std::string> il);
	size_type size() const { return data->size(); };
	bool empty() const { return data->empty(); };
	void push_back(const string& str) { data->push_back(str); };
	void pop_back();
	std::string& front();
	const std::string& front()const;
	std::string& back();
	const std::string& back() const;
	StrBlob(const StrBlob& b) :data(std::make_shared<vector<string>>(*b.data)) {

	};
	StrBlob& operator=(const StrBlob& d) {
		auto temp = std::make_shared<vector<string>>(*d.data);
		data = temp;
		return *this;
	};
	StrBlobPtr begin();
	StrBlobPtr end();

	ConstStrBlobPtr begin()const;
	ConstStrBlobPtr end()const;
//private:
	std::shared_ptr<vector<string>> data;
	void check(size_type i, const string& msg) const;
};

StrBlob::StrBlob() :data(std::make_shared<vector<string>>()) {

}


StrBlob::StrBlob(std::initializer_list<string> il) : data(std::make_shared<vector<string>>(il)) {

}

测试代码
StrBlob b({ "123","234" });
	StrBlob b1 = b;
	b1.push_back("233");
	for (const auto& item:*b.data) {
		cout << item << endl;
	}
	StrBlob b2;
	b2 = b1;
	b2.push_back("666");
	for (const auto& item : *b1.data) {
		cout << item << endl;
	}

13.2.2 acts like a pointer type

Want to define acts like a pointer type, we can use shared_ptr to achieve, or use the reference count of thought.

In the class definition of a variable, the variable points to a dynamically allocated memory, with the count.

The function of an assignment operator, the right operand counter ++, - left operand counter. If the counter is zero left of the object, a pointer to the memory is deleted.

For the first destructor - counter, and then determines whether the counter is 0, it is 0 to reclaim memory.

Exercise

13.28
class HasPtr {
public:
	HasPtr(const std::string& s = std::string()) :ps(new std::string(s)), i(0),ref_count(new size_t(1)) {};
	HasPtr(const HasPtr& hasptr) :ps(hasptr.ps), i(hasptr.i),ref_count(hasptr.ref_count) {
		++(*ref_count);
	};
	//列表初始化只能在构造函数中使用
	HasPtr& operator=(const HasPtr& p) {
		++*p.ref_count;
		if (--*ref_count==0) {
			delete ps;
			delete ref_count;
		}
		ps = p.ps;
		ref_count = p.ref_count;
		i = p.i;
		return *this;
	};
	~HasPtr() {
		if (--*ref_count==0) {
			delete ps;
			delete ref_count;
		}
	}
private:
	std::string *ps;
	int i;
	size_t* ref_count;
};
13.28

Mode control members used herein class value of two classes added.

Whether the object so that we do not have external incoming pipe is created dynamically.

class TreeNode {
public:
	TreeNode(const string& str, int c, TreeNode* l=nullptr, TreeNode* r=nullptr):value(str),count(c){
		if (l!=nullptr) {
			left = new TreeNode(*l);
		}
		if (r!=nullptr) {
			right = new TreeNode(*r);
		}
		
	};
	TreeNode(const TreeNode& t) :value(t.value),count(t.count){
		if (t.left!=nullptr) {
			left = new TreeNode(*t.left);
		}
		if (t.right!=nullptr) {
			right = new TreeNode(*t.right);
		}
	};
	TreeNode& operator=(const TreeNode& t) {
		TreeNode * l_temp = nullptr;
		if (t.left!=nullptr) {
			l_temp = new TreeNode(*t.left);
		}
		TreeNode* r_temp = nullptr;
		if (t.right!=nullptr) {
			r_temp = new TreeNode(*t.right);
		}
		left = l_temp;
		right = r_temp;
		value = t.value;
		count = t.count;
		return *this;
	};
	~TreeNode() {
		cout<<"~TreeNode"<<endl;
		delete left;
		delete right;
	}
private:
	string value;
	int count;
	TreeNode *left;
	TreeNode *right;
};

class BinStrTree {
public:
	BinStrTree(TreeNode* r) {
		if (r!=nullptr) {
			root = new TreeNode(*r);
		}
	};
	BinStrTree(const TreeNode& t) {
		root = new TreeNode(t);
	}
	BinStrTree& operator = (const BinStrTree& t) {
		//如果保存一份副本可能代价很大,所以直接判断,两个对象里面的root指针是否相等
		if (root!=t.root) {
			delete root;
		}
		root = new TreeNode(*t.root);
		return *this;
	}
	~BinStrTree() {
		delete root;
	}
private:
	TreeNode *root;
};
Published 54 original articles · won praise 6 · views 3302

Guess you like

Origin blog.csdn.net/zengqi12138/article/details/104484973