C++Primer: Chapter 12: smart pointer weakou PTR class

Posted by mattock on Tue, 21 Jan 2020 09:55:43 +0100

Class weak_ptr
Week_ptr is an intelligent pointer that does not control the lifetime of the object it points to. It points to an object managed by a shared_ptr. Binding a weakapuptr to shared apuptr does not change the reference count of shared apuptr. Once the last shared ﹐ PTR pointing to the object is destroyed, the object is released. Even if there is a leak uuptr pointing to the object, the object will be released

weak_ptr<T> w        //An empty weaku PTR can point to an object of type T
weak_ptr<T> w(sp)    //The peak PTR pointing to the same object as the shared PTR sp. T must be able to be converted to the type pointed to by SP
w = p                //p can be a shared_ptr or a weak_ptr. Shared object between w and p after assignment
w.reset()            //Set w to empty
w.use_count()        //The number of shared ﹣ PTRs of objects shared with w
w.expired()          //If w.use'count() is 0, return true, otherwise return false
w.lock()       //If the expired value is true, an empty shared \ u PTR is returned; otherwise, a shared \ u PTR of the object pointing to w is returned

When we create a weak uuptr, we need to initialize it with a shared uuptr:

auto p = make_shared<int>(42);
weak_ptr<int> wp(p);       //wp weak share P, reference count of P remains unchanged

Because the object may not exist, we can't directly access the object with the use of weakou PTR, but we must call lock. This function checks whether the object pointed to by the weakou PTR exists. If it exists, lock returns a shared "PTR" pointing to the shared object.

if (shared_ptr<int> np = wp.lock()){     //If np is not empty, the condition is true
	//In if, np and p share objects
}

Check pointer class
We will define an accompanying pointer class for the StrBlob class. Our pointer class will be named StrBlobPtr, which will save a weak_ptr, pointing to the data member of StrBlob, which is provided to it during initialization. With the use of weakapuptr, the lifetime of the vector pointed to by a given StrBlob is not affected. However, an attempt to access a vector that no longer exists can be blocked.

StrBlobPtr has two data members: wptr is either empty, or it points to a vector in StrBlob; curr, which saves the subscript of the element represented by the current object. Similar to its companion class StrBlob, our pointer also has a check member to check whether the dereference StrBlobPtr is safe:

//StrBlobPtr throws an exception for an attempt to access a nonexistent element
class StrBlobPtr {
	friend class StrBlob;
public:
	StrBlobPtr() : curr(0) { }
	StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) { }
	string& deref() const;
	StrBlobPtr& incr();     //Prefix increments
private:
	//If the check is successful, check returns a shared "PTR" pointing to the vector
	shared_ptr<vector<string>> check(size_t, const string&) const;
	//Saving a weak aputr means that the underlying vector may be destroyed
	weak_ptr<vector<string>> wptr;
	size_t curr;    //Current position in array
};

The default constructor generates an empty StrBlobPtr. Its constructor initialization list explicitly initializes curr to 0, and wptr implicitly initializes wptr to an empty weakou PTR.
The second constructor takes a StrBlob reference and an optional index value. This constructor initializes the wptr to point to the vector in the shared \ PTR of the given StrBlob object and initializes the curr to the value of sz. We use the default parameter to initialize curr as the subscript of the first element by default.

shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg) const {
	auto ret = wptr.lock();    //Does vector still exist? If there is a shared PTR that returns an object pointing to w
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;       //Otherwise, return the shared ﹣ PTR pointing to the vector
}

If the vector has been destroyed, lock returns a null pointer. In this case, any reference to a vector fails and an exception is thrown. Otherwise, check will check the given index. If the index value is legal, check will return the shared uuptr obtained from lock.

Pointer operation
Define functions named deref and incr to dereference and increment StrBlobPtr, respectively
The deref member calls check to check whether the vector is safe to use and whether the curr is within the legal range:

string& StrBlobPtr::deref() const {
	auto p = check(curr, "dereference past end");
	return (*p)[curr];     //(* p) is the vector that the object refers to
}

If check succeeds, p is a shared_ptr, pointing to the vector pointed to by StrBlobPtr. The expression (* p) [curr] dereferences shared Fu PTR to get the vector, and then uses the subscript operator to extract and return the element at the curr position.

//Prefix increment: returns the reference of the object after increment
StrBlobPtr& StrBlobPtr::incr() {
	//If the curl already points to the end of the container, it cannot be incremented
	check(curr, "increment past end of StrBlobPtr");
	++curr;    //Advance current position
	return *this;
}

In order to access data members, our pointer class must be declared as a friend of StrBlob. We also define the begin and end operations for the StrBlob class, returning a StrBlobPtr that points to itself:

class StrBlobPtr;
class StrBlob{
	StrBlobPtr begin(){return StrBlobPtr(*this);}
	StrBlobPtr end(){
		auto ret = StrBlobPtr(*this, data->size());
		return ret;
	}
}

Define your own version of StrBlobPtr, update the StrBlob class, add the appropriate friend declaration and begin and end members

#include <iostream>
#include <initializer_list>
#include <vector>
#include <string>
#include <memory>
using namespace std;
//Pre declaration, required by friend class declaration in StrBlob
class StrBlob {
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob();  //The default constructor assigns an empty vector
	//The constructor that accepts an initializer list passes its parameters to the corresponding vector constructor. This constructor initializes the elements in the vector by copying the values in the list
	StrBlob(initializer_list<string> il);
	size_type size() const { return data->size(); }
	bool empty() const { return data->empty(); }
	//Add and remove elements
	void push_back(const string& t) { data->push_back(t); }
	void pop_back();
	//Element access
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	//Interface provided to StrBlobPtr
	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<vector<string>> data;
	//Throw an exception if data[i] does not conform to the law 
	void check(size_type i, const string& msg) const;
};
inline StrBlob::StrBlob():data(make_shared<vector<string>>()){ }
inline StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)) {};
inline void StrBlob::check(size_type i, const string& msg) const {
	if (i >= data->size())
		throw out_of_range(msg);
}
inline string& StrBlob::front() {
	//If vector is empty, check throws an exception
	check(0, "front on empty StrBlob");
	return data->front();
}
inline const string& StrBlob::front() const{
	//If vector is empty, check throws an exception
	check(0, "front on empty StrBlob");
	return data->front();
}
inline string& StrBlob::back() {
	check(0, "back on empty StrBlob");
	return data->back();
}
inline const string& StrBlob::back() const{
	check(0, "back on empty StrBlob");
	return data->back();
}
inline void StrBlob::pop_back() {
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
class StrBlobPtr {
	friend bool eq(const StrBlobPtr&, const StrBlobPtr&);   //Comparison operation of StrBlobPtr
public:
	StrBlobPtr() : curr(0) { }
	StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) { }
	string& deref() const;  //Pointer operation
	StrBlobPtr& incr();     //Prefix increments
	StrBlobPtr& decr();     //Prefix decrement
private:
	//If the check is successful, check returns a shared "PTR" pointing to the vector
	shared_ptr<vector<string>> check(size_t, const string&) const;
	//Saving a weak aputr means that the underlying vector may be destroyed
	weak_ptr<vector<string>> wptr;
	size_t curr;    //Current position in array
};
inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string& msg) const {
	auto ret = wptr.lock();    //Does vector still exist? If there is a shared PTR that returns an object pointing to w
	if (!ret)
		throw runtime_error("unbound StrBlobPtr");
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;       //Otherwise, return the shared ﹣ PTR pointing to the vector
}
inline string& StrBlobPtr::deref() const {
	auto p = check(curr, "dereference past end");
	return (*p)[curr];     //(* p) is the vector that the object refers to
}
//Prefix increment: returns the reference of the object after increment
inline StrBlobPtr& StrBlobPtr::incr() {
	//If the curl already points to the end of the container, it cannot be incremented
	check(curr, "increment past end of StrBlobPtr");
	++curr;    //Advance current position
	return *this;
}
//Prefix decrement: returns the reference of the object after decrement
inline StrBlobPtr& StrBlobPtr::decr() {
	//If curr is already 0, decrement will result in an illegal subscript
	--curr;     //Decrement current position
	check(-1, "decrement past begin of StrBlobPtr");
	return *this;
}
inline StrBlobPtr StrBlob::begin() {
	return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end() {
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}
inline bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	//If the underlying vector is the same
	if (l == r)
		//Both pointers are null or point to the same element
		return (!r || lhs.curr == rhs.curr);
	else
		return false;      //Not equal if pointing to different vector s
}
inline bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {
	return !eq(lhs, rhs);
}
int main() {
	StrBlob b1;
	{
		StrBlob b2 = { "a", "an", "the" };
		b1 = b2;
		b2.push_back("about");
		cout << b2.size() << endl;
	}
	cout << b1.size() << endl;
	cout << b1.front() << " " << b1.back() << endl;
	const StrBlob b3 = b1;
	cout << b3.front() << " " << b3.back() << endl;
	cout << endl;
	for (auto it = b1.begin(); neq(it, b1.end()); it.incr())
		cout << it.deref() << endl;
	return 0;
}
Published 76 original articles, won praise 4, visited 2145
Private letter follow

Topics: curl