c + + standard library Chapter 5 general tools 5.2 smart pointers

1, Starting with c++11, the standard library provides two types of smart pointers

1,shared_ptr implements shared ownership. Multiple smart pointers can point to the same object. The object and its related resources will be released when the "last reference is destroyed". The standard library provides break_ ptr, bad_ weak_ PTR and enable_ shared_ from_ Auxiliary classes such as this

2,unique_ptr implements exclusive or strict ownership. Ensure that only one smart pointer can point to the object at the same time

2, Shared can be used like any other pointer_ PTR can be assigned, copied, compared, or the object it points to can be accessed by using the operators * and - > respectively

3, Shared_ When PTR accepts a single pointer as the constructor of the only argument, it is explicit, and the assignor cannot be used. You can declare the assignment first, but you can't assign directly. You must use reset()

4, shared_ptr uses * to get the object pointed to. Use - > to get a member within the object pointed to

5, Shared_ The default delete provided by PTR calls delete instead of delete [], so if you use new [], you must define your own delete

6, shared pointer is not thread safe

7, unique_ptr is a smart pointer that can help avoid resource leakage when an exception occurs. unique_ptr ensures that an object and its corresponding resources are owned by only one pointer at the same time. Once the owner is destroyed or becomes empty, or starts to own another object, the previously owned object will be destroyed and any corresponding resources will be released

8, unique_ptr does not allow an ordinary pointer to be used as the initial value in the assignment syntax. It must be initialized directly

9, unique_ptr does not necessarily have an object, but can also be empty. You can assign nullptr to it or call reset()

10, You can call release() to get unique_ptr owns the object and relinquishes ownership

11, Unique_ The PTR array version no longer provides the operators * and - >, but provides the operator [] to access an object in the array it points to. unique_ The default delete of PTR array version calls delete [], not delete. Conversions between different types are not supported, especially when pointing to derived element types is not allowed

12, unique_ptr ownership transfer enables functions to transfer ownership to other functions

1. The function is the receiving end. If a unique function established by std::move()_ PTR takes value reference as the function argument, then the parameter of the called function will get unique_ Ownership of PTR

2. The function is the supply side. When the function returns a unique_ptr, whose ownership will be transferred to the caller scenario

// Starting with c++11, the standard library provides two types of smart pointers
//shared_ptr implements shared ownership. Multiple smart pointers can point to the same object. The object and its related resources will be released when the "last reference is destroyed". The standard library provides break_ ptr, bad_ weak_ PTR and enable_ shared_ from_ Auxiliary classes such as this
//unique_ptr implements exclusive or strict ownership. Ensure that only one smart pointer can point to the object at the same time

// Ensure that when the last reference to a temporary file is destroyed, the file is closed and removed
class FileDeleter
{
private:
	string filename;
public:
	FileDeleter(const string& fn) : filename(fn) {}
	void operator()(ofstream* fp)
	{
		fp->close();
		std::remove(filename.c_str());
	}
};

//Shared can be used like any other pointer_ PTR can be assigned, copied, compared, or the object it points to can be accessed by using the operators * and - > respectively
void sharedPtrLearn()
{
	shared_ptr<string> pHello(new string("hello"));
	// When the constructor that accepts a single pointer as the only argument is explicit, the assignor cannot be used
	//shared_ptr<string> pHello2 = new string("hello");
	// You can use make_shared
	//shared_ptr<string> pHello2 = make_shared<string>("hello");
	//You can declare the assignment first, but you can't assign directly. You must use reset()
	//shared_ptr<string> pHello2;
	//pHello2 = new string("hello"); //  error
	//pHello2.reset(new string("hello")); //  correct
	shared_ptr<string> pWorld(new string("world"));
	// Use * to get the object pointed to
	(*pHello)[0] = 'H';
	//Use - > to get a member within the object pointed to
	pWorld->replace(0, 1, "W");
	cout << *pHello << endl;

	vector<shared_ptr<string>> helloWorld;
	helloWorld.push_back(pWorld);
	helloWorld.push_back(pWorld);
	helloWorld.push_back(pHello);
	helloWorld.push_back(pWorld);
	helloWorld.push_back(pHello);
	for (auto ptr : helloWorld)
	{
		cout << *ptr << " ";
	}
	cout << endl;

	*pHello = "Hi";
	for (auto ptr : helloWorld)
	{
		cout << *ptr << " ";
	}
	cout << endl;

	// You can declare your own delete
	shared_ptr<string> pHello2(new string("hello"),
		[](string* p) {
			cout << "delete: " << *p << endl;
			delete p;
		});
	// shared_ The default delete provided by PTR calls delete instead of delete [], so if you use new [], you must define your own delete
	//shared_ ptr<int> p(new int[10]); //  Can pass, but it's wrong
	shared_ptr<int> p(new int[10], 
		[](int* p) {
			delete[] p;
		});

	// When the last copy of shared pointer loses ownership of this output file through a custom class, the file is closed and removed by the remove() provided by < cstdio >
	shared_ptr<ofstream> fp(new ofstream("test.txt"), FileDeleter("test.txt"));
}


class Person : public std::enable_shared_from_this<Person>
{
public:
	string name;
	shared_ptr<Person> mother;
	shared_ptr<Person> father;
	//vector<shared_ptr<Person>> kids;
	vector<weak_ptr<Person>> kids;

	Person(const string& n, shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr) : name(n), mother(m), father(f)
	{

	}

	~Person()
	{
		cout << "delete" << name << endl;
	}

	void setParentAndTheirKids(shared_ptr<Person> m = nullptr, shared_ptr<Person> f = nullptr)
	{
		mother = m;
		father = f;
		if (m != nullptr)
		{
			m->kids.push_back(shared_from_this());
		}
		if (f != nullptr)
		{
			f->kids.push_back(shared_from_this());
		}
	}
};

shared_ptr<Person> initFamily(const string& name)
{
	shared_ptr<Person> mom(new Person(name + "'s mom"));
	shared_ptr<Person> dad(new Person(name + "'s dad"));
	shared_ptr<Person> kid(new Person(name, mom, dad));
	mom->kids.push_back(kid);
	dad->kids.push_back(kid);
	return kid;
}

void testPerson()
{
	shared_ptr<Person> p = initFamily("nico");
	cout << "-nico's family exists" << endl;
	cout << "-nico is shared " << p.use_count() << " times " << endl;
	//cout << "-name of 1st kid of nico's mom:" << p->mother->kids[0]->name << endl;
	cout << "-name of 1st kid of nico's mom:" << p->mother->kids[0].lock()->name << endl;
	p = initFamily("jim");
	cout << "jim's family exists" << endl;
}

/*template<typename T>
//shared pointer Not thread safe
class share_ptr
{
public:
	typedef T element_type;
};*/

/*class ClassA
{

};

void errorFoo()
{
	ClassA* ptr = new ClassA;
	delete ptr;// delete It may not be executed, such as the return statement in the middle, throwing an exception, etc
}
void goodFoo()
{
	// Using unique_ptr
	std::unique_ptr< ClassA> ptr(new ClassA);
}*/
// unique_ptr is a smart pointer that can help avoid resource leakage when an exception occurs
// unique_ptr ensures that an object and its corresponding resources are owned by only one pointer at the same time
//Once the owner is destroyed or becomes empty, or starts to own another object, the previously owned object will be destroyed and any corresponding resources will be released
void uniquePtrLearn()
{
	//unique_ptr<string> up(new string("hello"));
	//Use the * operator to point to an object
	//(*up)[0] = 'H';
	//Use operator - > access member
	//up->append("world");
	//cout << *up << endl;
	// unique_ptr does not allow an ordinary pointer to be used as an initial value in assignment syntax
	//unique_ ptr<int> up = new int; // error
	//Must be initialized directly
	//unique_ptr<int> up(new int);
	//unique_ptr does not necessarily have an object, but can also be empty
	//unique_ptr<string> up;
	// You can give it nullptr or call reset()
	//up = nullptr;
	//up.reset();
	//You can call release() to get unique_ptr owns the object and relinquishes ownership
	unique_ptr<string> up(new string("hello"));
	string* sp = up.release();
	// It can be judged that the uniue pointer has released any object
	//if (up){}
	//Can be compared with nullptr
	if (up != nullptr) {}
	if (up.get() != nullptr) {}

	//unique_ptr to array
	unique_ptr < string[]> up2(new string[10]);
	//unique_ The PTR array version no longer provides the operators * and - >, but provides the operator [] to access an object in the array it points to
	//unique_ The default delete of PTR array version calls delete [], not delete
	//Conversion between different types is not supported. In particular, it is not allowed to point to derived element types
	//cout << *up2 << endl; // error
	cout << up[0] << endl;//correct
}

//unique_ptr ownership transfer enables functions to transfer ownership to other functions
//The function is the receiving end. If a unique function established by std::move()_ PTR takes value reference as the function argument, then the parameter of the called function will get unique_ Ownership of PTR
void sink(unique_ptr<string> up) {}
void testSink()
{
	unique_ptr<string> up(new string("hello"));
	sink(std::move(up));
}
//The function is the supply side. When the function returns a unique_ptr, whose ownership will be transferred to the caller scenario
unique_ptr<string> source()
{
	unique_ptr<string> ptr(new string("hello"));
	// The return statement does not require std::move() because c + + stipulates that the compiler should automatically try to add move
	return ptr;
}
void testSource()
{
	unique_ptr<string> p;
	for (int i = 0; i < 10; ++i)
	{
		// Whenever source() is called, it creates an object with new and returns it to the caller with its ownership
		// The return value is assigned to p, and ownership is transferred to p
		//In the second iteration, assigning a value to p causes the object previously owned by P to be deleted
		//Once testSource() ends, p is destroyed, causing the last object owned by p to be destructed
		p = source();
	}
}


class ClassA
{
public:
	ClassA(int val) {};
};
class ClassB
{
private:
	// If unique is used_ PTR replaces the ordinary pointer, so the destructor is no longer needed
	//Only when all construction actions are completed can the destructor be called
	//Therefore, once an exception occurs during construction, only those objects that have been completely constructed will have their destructors called
	//ClassA* ptr1;
	//ClassA* ptr2;
	unique_ptr<ClassA> ptr1;
	unique_ptr<ClassA> ptr2;
public:
	ClassB(int val1, int val2) : ptr1(new ClassA(val1)), ptr2(new ClassA(val2))
	{

	}
	ClassB(const ClassB& x) : ptr1(new ClassA(*x.ptr1)), ptr2(new ClassA(*x.ptr2))
	{

	}
	const ClassB& operator=(const ClassB& x)
	{
		*ptr1 = *x.ptr1;
		*ptr2 = *x.ptr2;
		return *this;
	}
	/*~ClassB()
	{
		delete ptr1;
		delete ptr2;
	}*/
};

int main()
{
	//sharedPtrLearn();
	//testPerson();
	uniquePtrLearn();
	return 0;
}

Keywords: C++

Added by jimbob on Mon, 24 Jan 2022 23:42:44 +0200