The Shared_ptr Class(memory header)

Initialization

1.A default initialized smart pointer holds a null pointer.

shared_ptr<vector<string>> p;  // shared_ptr that can point at a vector of string.

2.Using make_shared function allocates and initializes an object in dynamic memeory and returns a shared ptr hat points to that object.

  • We bind a shared_ptr to the object at the same time we allocate it.
auto p = make_shared<vector<string>>(10,'9');  // P points to a string with value 9999999999.

3.Initializing a smart ptr from a pointer returned by new.

  • must use direct initialization.
  • can't implicitly convert a plain ptr to a smart ptr.
shared_ptr<int> p1 = new int(1024);  // error:must use direct initialization.(not copy initialization)
shared_ptr<int> p2(new int(1024));  // ok:uses direct initialization.

shared_ptr<int> clone(int p){
    return new in(p);    // error:implicit conversion to shared_ptr<int>.
}
shared_ptr<int> clone(int p){
    return shared_ptr<int>(new in(p));    // ok:explicitly create a shared_ptr<int> from int*.
}

Copying and Assigning

1.We can think of a shared_ptr as if it has an associated counter, usually referred to as a reference count.

Counter incremented when:

  • use it(shared_ptr) as the right-hand operand of an assignment(copy);
  • pass it to or return it from a function by value.

Counter decremented when:

  • assign a new vale to the shared_ptr.
  • a local shared_ptr goes out of scope.

Once a shared ptr's counter goes to zero, the shared_ptr automatically frees the object that it manages.
Memory is not freed until the last shared_ptr goes away.

Classes with resources that have dynamic lifetime

1.Each vector "owns" its own elememts. When we copy a vector, the elements in the original vector and in the copy are separate from one another.

vector<string> v1;
{  // new scope.
    vector<string> v2 = {"a", "an", "the"};
    v1 = v2;  // copies the elements from v2 into v1.
}  // v2 is destroyed, which destroys the elements in v2.
   // v1 has three elements, which are copies of the ones originally in v2.
  • The elements allocated by a vector exist only while the vector itself exists.

2.Use dynamic memory to allow multiple objects to share the same state(data).

  • To ensure that the elements continue to exist, we'll store the vector in dynamic memory.
  • We want Blob objects that are copies of one another to share the same elements.
Blob<string> b1;  // empty Blob
{  // new scope
    Blob<string> b2 = {"a", "an", "the"};
    b1 = b2;  // b1 and b2 share the same elements
}  // b2 is destroyed, but the elements in b2 must not be destroyed
   // b1 points to the elments originally created in b2.
  • Define the StrBlob Class as below:
StrBlob.h
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <stdexcept>

using namespace std;

class StrBlob {
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string> il);  // initializer_list is a library type that represents
	                                       // an array of values of the specified type.
	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();

	string& front();
	string& back();

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

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

void StrBlob::check(size_type i, const string& msg) const {
	if (i >= data->size())
		throw out_of_range(msg);
}

string& StrBlob::front() {
	check(0, "front on empty StrBlob");
	return data->front();
}

string& StrBlob::back() {
	check(0, "back on empty StrBlob");
	return data->back();
}

void StrBlob::pop_back() {
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
#endif // !MY_STRBLOB_H


StrBlob.cpp
#include <iostream>
#include "Strblob.h"

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;

	StrBlob b3 = b1;
	cout << b3.front() << " " << b3.back() << endl;

	return 0;
}
// output:
// 4
// 4
// a about
// a about

Smart Ptr Pitfalls

1.A shared_ptr can coordinate destruction only with other shared_ptr that are copies of itself.

When we bind a shared_ptr to a plain pointer, it makes two independent reference count, one goes zero to free the memory, makes another dangling.
There is no way to inadvertently bind the same memory to more than one independently created shared_ptr.

  • Don't use the same built-in pointer value to initialize (or reset) more than one smart ptr.
  • Don't delete the pointer returned from get().
  • Don't use get() to initialize or reset another smart ptr.
  • If you use a ptr returned by get(), remember that the ptr will become invalid when the last corresponding smart pointer goes away.
  • If you use a smart ptr to manage a resource other than memory allocated by new, remember to pass a deleter.
posted @ 2022-02-08 21:51  Dy2MoRaw  阅读(66)  评论(0)    收藏  举报