C++06智能指针new,malloc,free,delete的区别

1.裸指针和智能指针

头文件#include

智能指针 智能:无论如何,保证资源 一定会释放
内存:.data .heap

1.1智能指针原理:

利用栈上的对象出作用域自动析构的特点,把
资源释放的代码,放在智能指针的析构函数里面

1.2不带引用计数的智能指针(一个资源 =》 一个智能指针)

auto_ptr C++11之前 C++库里面有的
只有最后一个智能指针有效
scoped_ptr 把拷贝构造和operator=给delete掉了

#include
unique_ptr 把拷贝构造和operator=给delete掉了

1.3带引用计数的智能指针(一个资源 =》 多个智能指针)

#include
unique_ptr 把拷贝构造和operator=给delete掉了

带引用计数的智能指针(一个资源 =》 多个智能指针)
#include
shared_ptr 强(引起资源引用计数的改变)智能指针
weak_ptr 弱(不会引起资源引用计数的改变)智能指针
// ++ --操作 加锁的方式 CAS方式
是线程安全的智能指针

智能指针的删除器Deletor:自定义资源的释放方式 一元函数对象operator()

=======================================================
1> 带引用计数的智能指针的循环应用问题
2> 带引用计数的智能指针能不能解决多线程访问共享对象的线程安全问题
3> unique_ptr到底怎么回事

class B;
class A
{
public:
	A() { cout << "A()" << endl; }
	~A() { cout << "~A()" << endl; }
	weak_ptr<B> _ptrb;

	void testA() { cout << "A类中很强大的一个方法实现!" << endl; }
};
class B
{
public:
	B() { cout << "B()" << endl; }
	~B() { cout << "~B()" << endl; }
	weak_ptr<A> _ptra;
	// operator*  operator->

	void func()
	{
		// promote 提升 弱 -》 强(引用计数 1)
		// shared_ptr   operator== !=  nullptr
		shared_ptr<A> sp =  _ptra.lock();
		if (sp != nullptr)
		{
			// 提升成功了(说明资源还在)
			sp->testA();
		}
		else
		{
			// 提升失败了(说明资源已经不存在了)
		}
	}
};
int main()
{
	// 用引用计数解决问题,有一个bug
	shared_ptr<A> pa(new A());
	shared_ptr<B> pb(new B());

	pa->_ptrb = pb;
	pb->_ptra = pa;

	cout << pa.use_count() << endl;
	cout << pb.use_count() << endl;

	pb->func();

	return 0;
}
#endif

#if 0
// 记录资源的引用计数类 C++STL库里面容器的增加,删除 不是线程安全
class RefCnt
{
public:
	// 给资源添加引用计数
	void add(void *ptr)
	{
		auto it = mrefCntMap.find(ptr);
		if (it != mrefCntMap.end())
		{
			it->second++;
		}
		else
		{
			// make_pair(ptr,1);
			mrefCntMap.insert({ ptr, 1 });
		}
	}
	// 给资源减少引用计数
	void del(void *ptr)
	{
		auto it = mrefCntMap.find(ptr);
		if (it != mrefCntMap.end())
		{
			if (--(it->second) == 0)
			{
				//mrefCntMap.erase(it);
			}
		}
	}
	// 返回指定资源的引用计数
	int get(void *ptr)
	{
		auto it = mrefCntMap.find(ptr);
		if (it != mrefCntMap.end())
		{
			return it->second;
		}
		return 0;
	}
private:
	// 一个资源void* 《=》 计数器 int
	unordered_map<void*, int> mrefCntMap;
};

// 提供一个默认的删除器,默认删除的是堆内存资源
template<typename T>
class Deletor
{
public:
	void operator()(T *ptr) // 一元函数对象
	{
		delete ptr; // 默认删除的是堆内存资源
	}
};
// 自定义的智能指针 T资源的类型   D删除器的类型
template<typename T, typename D = Deletor<T>>
class CSmartPtr
{
public:
	// 构造函数
	CSmartPtr(T *ptr = nullptr, const D &d=D())
		:mptr(ptr), mdeletor(d)
	{
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}
	}
	~CSmartPtr()
	{
		mrefCnt.del(mptr);
		if (0 == mrefCnt.get(mptr))
		{
			cout << "释放默认的堆内存资源" << endl;
			mdeletor(mptr); // 通过删除器来释放资源
		}
		//delete mptr;
	}
	CSmartPtr(const CSmartPtr<T> &src)
		:mptr(src.mptr)
	{
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}
	}
	CSmartPtr<T>& operator=(const CSmartPtr &src)
	{
		if (this == &src)
			return *this;

		mrefCnt.del(mptr);
		if (0 == mrefCnt.get(mptr))
			delete mptr;

		mptr = src.mptr;
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}

		return *this;
	}
	/* auto_ptr的实现方式
	CSmartPtr(CSmartPtr &src)
	{
		mptr = src.release();
	}

	T* release()
	{
		T *ptmp = mptr;
		mptr = nullptr;
		return ptmp;
	}*/

	// 指针常用运算符重载函数
	T& operator*() { return *mptr; }
	const T& operator*()const { return *mptr; }
	T* operator->() { return mptr; }

	// scoped_ptr的实现方式
	// CSmartPtr(const CSmartPtr<T>&) = delete;
	// CSmartPtr<T>& operator=(const CSmartPtr<T>&) = delete;
private:
	T *mptr;  // FILE *pf;    delete pf;   fclose(pf);
	D mdeletor;
	static RefCnt mrefCnt;
};
template<typename T, typename D>
RefCnt CSmartPtr<T, D>::mrefCnt;

int main()
{
	// 智能指针  管理资源 =》  堆内存 文件
	CSmartPtr<int> ptr2(new int);

	class FileDeletor
	{
	public:
		void operator()(FILE *pf) const
		{ 
			cout << "释放文件资源" << endl;
			fclose(pf); 
		}
	};
	CSmartPtr<FILE, FileDeletor> ptr(fopen("data.txt", "w+"));

	// mdeletor(mptr);                     
	// CSmartPtr<FILE> ptr3(fopen("data1.txt", "w+"), [](FILE *pf)->void { cout << "xxx" << endl; });
	// delete p;
	
	unique_ptr<int> ptr3(new int);

	unique_ptr<FILE, FileDeletor> ptr4(fopen("d", "w+"));
	unique_ptr<FILE> ptr5(fopen("dd", "w+")});

	return 0;
}

1.4实现智能指针

// 自定义的智能指针
template<typename T>
class CSmartPtr
{
public:
	// 构造函数
	CSmartPtr(T *ptr = nullptr)
		:mptr(ptr) 
	{
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}
	}
	~CSmartPtr() 
	{ 
		mrefCnt.del(mptr);
		if(0 == mrefCnt.get(mptr))
			delete mptr; 
	}
	CSmartPtr(const CSmartPtr<T> &src)
		:mptr(src.mptr)
	{
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}
	}
	CSmartPtr<T>& operator=(const CSmartPtr &src)
	{
		if (this == &src)
			return *this;

		mrefCnt.del(mptr);
		if (0 == mrefCnt.get(mptr))
			delete mptr;

		mptr = src.mptr;
		if (mptr != nullptr)
		{
			mrefCnt.add(mptr);
		}

		return *this;
	}
	/* auto_ptr的实现方式
	CSmartPtr(CSmartPtr &src)
	{
		mptr = src.release();
	}

	T* release()
	{
		T *ptmp = mptr;
		mptr = nullptr;
		return ptmp;
	}*/

	// 指针常用运算符重载函数
	T& operator*() { return *mptr; }
	const T& operator*()const { return *mptr; }
	T* operator->() { return mptr; }

	// scoped_ptr的实现方式
	// CSmartPtr(const CSmartPtr<T>&) = delete;
	// CSmartPtr<T>& operator=(const CSmartPtr<T>&) = delete;
private:
	T *mptr;
	static RefCnt mrefCnt;
};
template<typename T>
RefCnt CSmartPtr<T>::mrefCnt;

int main()
{
	CSmartPtr<int> ptr1(new int);
	CSmartPtr<int> ptr2 = ptr1;

	*ptr2 = 20;
	*ptr1 = 30;

	CSmartPtr<int> ptr3(new int);
	ptr2 = ptr3;

	auto_ptr<int> p;
	// auto_ptr能不能用在容器当中
	/* vector<auto_ptr<int>> vec;
		vec.push_back(auto_ptr<int>(new int));

		vector<auto_ptr<int>> vec1 = vec;
	*/
	return 0;
}

#if 0
int main()
{
	CSmartPtr<int> ptr1(new int);
	*ptr1 = 20; // T operator*()
	
	class Test
	{
	public:
		void test() { cout << "call Test::test" << endl; }
	};
	CSmartPtr<Test> ptr2(new Test());
	ptr2->test();  // (ptr2.operator->())->test();
	(*ptr2).test();

	// 能不能在堆上直接定义智能指针
	//CSmartPtr<int> *ptr2 = new CSmartPtr<int>(new int);
	//delete ptr2;
	return 0;
}

1.5解决内存泄漏问题

class CMemLeakCheck
{
public:
~CMemLeakCheck()
{

}

private:
unordered_set<void*> memList;
};

// 定义一个内存泄露检查的全局对象
CMemLeakCheck memleakCheck;

2.右值引用,左值引用

int main()
{
	// C++11 右值引用   左值引用(叫得上名字,取得上地址)
	int a = 10;
	int &b = a;
	const int &c = 20;  // c = 30;
	int &&d = 20;
	d = 30;
	return 0;
}

2.1

template<typename T>
class CStack
{
public:
	CStack(int size = 100000)
		:mtop(0)
	{
		cout << "CStack()" << endl;
		mpstack = new T[size];
	}
	~CStack()
	{
		cout << "~CStack()" << endl;
		delete[]mpstack;
	}
	CStack(const CStack<T> &src)
		:mtop(src.mtop)
	{
		cout << "CStack(const CStack<T> &src)" << endl;
		mpstack = new T[100000];
		for (int i = 0; i < mtop; ++i)
		{
			mpstack[i] = src.mpstack[i];
		}

		//mpstack = src.mpstack;
		//src.mpstack = nullptr;
	}
	// 提供带右值引用参数的拷贝构造函数
	CStack(CStack<T> &&src)
		:mtop(src.mtop)
	{
		cout << "CStack(CStack<T> &&src)" << endl;
		mpstack = src.mpstack;
		src.mpstack = nullptr;
	}
	CStack<T>& operator=(const CStack<T> &src)
	{
		cout << "operator=" << endl;
		if (this == &src)
			return *this;

		delete[]mpstack;

		mtop = src.mtop;
		mpstack = new T[100000];
		for (int i = 0; i < mtop; ++i)
		{
			mpstack[i] = src.mpstack[i];
		}
		return *this;
	}
	CStack<T>& operator=(CStack<T> &&src)
	{
		cout << "operator=(&&)" << endl;
		if (this == &src)
			return *this;

		delete[]mpstack;

		mtop = src.mtop;
		mpstack = src.mpstack;
		src.mpstack = nullptr;
		return *this;
	}
	void push(const T &val)
	{
		mpstack[mtop++] = val;
	}
private:
	T *mpstack;
	int mtop;
};
CStack<int> GetStackObject()
{
	CStack<int> s;
	s.push(20);
	s.push(30);
	s.push(40);
	return s;
}
int main()
{
	CStack<int> s1;
	CStack<int> s2(std::move(s1));  // std::move

	s2 = GetStackObject();

	return 0;
}

3面试题

3.1map的使用

tring name; 种类名称  
Action action;动作   
Time time:时间
class Function
{
	public: 
		// map<string, list<Action>>
		list<Action> getAction(string name);
		// map<Time, Action>
		list<Action> getActions(int n);
		// map<string, map<Time, Action>>  struct Data{Action,Time};
		list<Action> getActions(string name, int n);
	private:
		 map<, >
};

3.2三种new分别说一下

new int(10)
new nothorw int(10);
new (addr) int(10);
const int * p = new const int(10);

函数对象
greater less greater_equal less_equal

3.3new和delete的重载

// C++实现垃圾回收器  new Node  delete (Node*)ptr;

// 对象池的初始个数
const int MEM_NODE_SIZE = 5;

template<typename T>
class CLink
{
public:
	CLink() { mphead = new Node(); }
	~CLink();
	void insertTail(const T &val);
	void removeHead();
	void show();
private:
	struct Node
	{
		Node(T data = T()) :mdata(data), mpnext(nullptr) {}
		/*
		给Node类型提供new和delete运算符的重载,
		自定义Node对象的内存管理方式,实现Node对象池功能
		*/
		void* operator new(size_t size)
		{
			if(mpObjectPool ==nullptr)
			{
				mpObjectPool =
					(Node *)new char(MEM_NODE_SIZE *sizeof (Node ));
				Node *pcur=mpObjectPool ;
				for(;pcur <mpObjectPool+MEM_NODE_SIZE  -1;++pcur)
				{
					pcur ->mpnext =pcur+1;
				}
				pcur ->mpnext =nullptr;
			}
			Node *palloc=mpObjectPool ;
			mpObjectPool =mpObjectPool ->mpnext;
			return palloc ;
		}
		void operator delete(void *ptr)
		{
			Node *pfree=(Node *)ptr;
			pfree ->mpnext =mpObjectPool ;
			mpObjectPool=pfree ;
		}
		T mdata;
		Node *mpnext;
		// 添加一个指向对象池的起始地址的指针
		static Node *mpObjectPool;
	};

	Node *mphead;
};
int main()
{
	return 0;
}

class Test
{
public:
	Test() :mptr(new int(0)) { cout << "Test()" << endl; }
	~Test() { delete mptr; cout << "~Test()" << endl; }

	// Test对象的内存开辟释放会调用到这里 默认都是static方法
	void* operator new(size_t size) // 只负责内存开辟
	{
		void *p = nullptr;
		p = malloc(size);
		if (p == nullptr)
			throw bad_alloc();
		cout << "operator new addr: " << p << endl;
		return p;
	}
	void operator delete(void *ptr) // 只负责释放内存
	{
		cout << "operator delete addr:" << ptr << endl;
		free(ptr);
	}
	void* operator new[](size_t size) // 只负责内存开辟
	{
		void *p = nullptr;
		p = malloc(size);
		if (p == nullptr)
			throw bad_alloc();
		cout << "operator new[] addr:" << p << endl;
		return p;
	}
		void operator delete[](void *ptr) // 只负责释放内存
	{
		cout << "operator delete[] addr:" << ptr << endl;
		free(ptr);
	}
private:
	int *mptr;
};

3.4new和malloc的区别?

1.malloc 库函数 new运算符
2.malloc new
3.malloc(void*) new int(10)
4.malloc new int20;

3.5free和delete的区别

1.delete 析构 free
2.delete free
Test p = new Test;
3.delete (int
)p;(敏感) free(ptr);
4.free(ptr) delete []ptr;

4.多线程访问共享对象问题

#if 0
class Test
{
public:
	Test(const char *ptr) :mptr(new char[strlen(ptr) + 1])
	{
		cout << "Test()" << endl;
		strcpy(mptr, ptr);
	}
	~Test() 
	{
		cout << "~Test()" << endl;
		delete[]mptr; 
		mptr = nullptr;
	}
	void show() { cout << mptr << endl; }
private:
	char *mptr;
};
// 子线程   p
void thread_proc(weak_ptr<Test> wp, const char *threadname)
{
	cout << threadname << endl;
	// 睡眠2s
	std::this_thread::sleep_for(std::chrono::seconds(2));
	cout << "子线程2s睡眠已到!" << endl;

	//p->show();
	/*
	这个线程在提升的过程中,刚好其它线程在释放
	*/
	shared_ptr<Test> sp = wp.lock();  // 2-1 = 1
	if (sp != nullptr)
	{
		sp->show();
	}
	else
	{
		cout << "Test对象已经析构,不能继续访问!" << endl;
	}
}

void func()
{
	//Test *p = new Test("hello world");
	shared_ptr<Test> p(new Test("hello world"));
	// 创建线程对象,就自动开启线程了
	/*
	thread(xx, shared_ptr<Test> p)
	*/
	thread t1(thread_proc, weak_ptr<Test>(p), "child thread");
	// pthread_create

	t1.join();
	//t1.detach(); // 设置子线程为分离线程

	//delete p;
	// t1.join   pthread_join
	// t1.detach pthread_detach  设置分离线程
	cout << "main thread end!" << endl;
} //1 - 1 = 0
int main()
{
	cout << "main thread begin!" << endl;
	func();
	// 主线程等待20秒,查看子线程的运行情况
	std::this_thread::sleep_for(std::chrono::seconds(20));
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/sunshinecandy/article/details/89280962
今日推荐