C++进阶—智能指针

基于VS2012 C#调用bartender自动打印条形码 GitHub:https://github.com/sanjaywu/BarcodePrintTool 一、在引用添加Interop.BarTender.dll 1、在资源解决方案的引用这里,右击选择“添加引用”: 2、按照如下步骤添加Interop.BarTender.dll引用: 3、添加完成 二、使用bartender工具设置打印模板 1、页面大小设置: 2、条码设置: 三、代码... 阅读详情

第一章:为什么需要智能指针?

double Division(int len, int time) {
	if (time == 0) throw invalid_argument("除0错误");
	return (double)len / (double)time;
}

void Func() {
	int* p = new int[10];

	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;//如果抛异常,这行之后的语句都不会执行

	delete[] p;//抛异常会导致p未释放
	cout << "delete[] " << p << endl;
}

int main() {
	try {
		Func();
	}
	catch (exception& e) {
		cout << e.what() << endl;
	}
	return 0;
}

在 Division 函数中抛出异常,会导致 Func 函数中的 delete[] p 无法执行,从而引发内存泄漏。虽然可以在 Func 内部捕获异常、释放内存后重新抛出,但这会导致代码变得复杂且难以维护,特别是当有多个需要释放的资源时。

第二章:内存泄漏

2.1 什么是内存泄漏,内存泄漏的危害

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。

2.2 内存泄漏分类

C/C++程序中一般我们关心两种方面的内存泄漏:

堆内存泄漏(Heap leak)
堆内存指的是程序执行中依据须要分配通过malloc / calloc / realloc / new等从堆中分配的一块内存,用完后必须通过调用相应的 free或者delete 删掉。假设程序的设计错误导致这部分内存没有被释放,那么以后这部分空间将无法再被使用,就会产生Heap Leak。

系统资源泄漏
指程序使用系统分配的资源,比方套接字、文件描述符、管道等没有使用对应的函数释放掉,导致系统资源的浪费,严重可导致系统效能减少,系统执行不稳定。

2.3 如何检测内存泄漏

2.4如何避免内存泄漏

  1. 工程前期良好的设计规范,养成良好的编码规范,申请的内存空间记着匹配的去释放。ps:这个理想状态。但是如果碰上异常时,就算注意释放了,还是可能会出问题。需要下一条智能指针来管理才有保证。
  2. 采用RAII思想或者智能指针来管理资源。
  3. 有些公司内部规范使用内部实现的私有内存管理库。这套库自带内存泄漏检测的功能选项。
  4. 出问题了使用内存泄漏工具检测。ps:不过很多工具都不够靠谱,或者收费昂贵。

总结一下:
内存泄漏非常常见,解决方案分为两种:1、事前预防型。如智能指针等。2、事后查错型。如泄漏检测工具。

第三章:智能指针的使用及原理

3.1 RAII

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

  • 不需要显式地释放资源。
  • 采用这种方式,对象所需的资源在其生命期内始终保持有效。
// 使用RAII思想设计的SmartPtr类
class SmartPtr {
public:
	SmartPtr(int* ptr)
		:_ptr(ptr) {
	}

	~SmartPtr() {
		delete[] _ptr;
		cout << "delete[] " << _ptr << endl;
	}
private:
	int* _ptr;
};
double Division(int len, int time) {
	if (time == 0) throw invalid_argument("除0错误");
	return (double)len / (double)time;
}
void Func() {
	int* p = new int[10];
	//用智能指针释放,无论是否抛异常都能正常释放
	SmartPtr<int> sp(p);
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
}
//不抛异常时的执行流程:Func() 函数结束,sp是栈对象,离开作用域时自动调用 ~SmartPtr()。
//抛异常时的执行流程:由于异常抛出,Func() 的当前执行被中断,栈展开(Stack Unwinding) 开始:
//C++会析构 Func()中的所有栈对象(这里是sp)。sp.~SmartPtr() 被调用,执行 delete[] _ptr,释放内存。
int main() {
	try {
		Func();
	}
	catch (exception& e) {
		cout << e.what() << endl;
	}

	return 0;
}

改为模板

template <class T>
class SmartPtr {
public:
	SmartPtr(T* ptr)
		:_ptr(ptr) {
	}

	~SmartPtr() {
		delete[] _ptr;
		cout << "delete[] " << _ptr << endl;
	}
private:
	T* _ptr;
};

double Division(int len, int time) {
	if (time == 0) throw invalid_argument("除0错误");
	return (double)len / (double)time;
}

void Func() {
	//RAII
	//1.资源获取(Acquisition):new int[10] 动态分配 10 个 int 的内存空间(资源获取)。
	//2.立即初始化管理对象(Initialization)
	//将原始指针 int* 立即传递给 SmartPtr<int> 的构造函数,由 sp1 接管所有权。
	//3.生命周期绑定
	//sp1 是栈对象,其析构函数会在 Func() 结束时(无论正常返回或异常)自动调用,释放 int[10]。
	SmartPtr<int> sp1(new int[10]);
	SmartPtr<double> sp2(new double[10]);
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
}

int main() {
	try {
		Func();
	}
	catch (exception& e) {
		cout << e.what() << endl;
	}

	return 0;
}

3.2 智能指针的原理

上述的SmartPtr还不能将其称为智能指针,因为它还不具有指针的行为。指针可以解引用,也可以通过->去访问所指空间中的内容,因此:AutoPtr模板类中还得需要将* 、->重载下,才可让其像指针一样去使用。

template<class T>
class SmartPtr {
public:
	SmartPtr(T* ptr)
		:_ptr(ptr) {
	}

	~SmartPtr() {
		delete _ptr;
		cout << "~SmartPtr() -> " << _ptr << endl;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }

private:
	T* _ptr;
};

总结一下智能指针的原理:

  1. RAII特性
  2. 重载operator*和opertaor->,具有像指针一样的行为。

3.3 std::auto_ptr

C++98版本的库中就提供了auto_ptr的智能指针。下面演示的auto_ptr的使用及问题。
auto_ptr的实现原理:管理权转移的思想,下面简化模拟实现了一份bit::auto_ptr来了解它的原理。

template<class T>
class auto_ptr {
public:
	auto_ptr(T* ptr)
		:_ptr(ptr) {
	}

	~auto_ptr() {
		if (_ptr) {
			delete _ptr;
			cout << "delete->" << _ptr << endl;
			_ptr = nullptr;
		}
	}

	//管理权转移 ap2(ap1)
	auto_ptr(auto_ptr<T>& ap)
		:_ptr(ap._ptr) {
		ap._ptr = nullptr;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }

private:
	T* _ptr;
};

int main() {
	std::auto_ptr<int> sp1(new int);
	std::auto_ptr<int> sp2(sp1); // 管理权转移

	// sp1悬空
	*sp2 = 10;
	cout << *sp2 << endl;
	cout << *sp1 << endl;
	return 0;
}
// 结论:auto_ptr是一个失败设计,很多公司明确要求不能使用auto_ptr

3.4 std::unique_ptr

C++11中开始提供更靠谱的unique_ptr

unique_ptr文档

unique_ptr的实现原理:简单粗暴的防拷贝,下面简化模拟实现了一份UniquePtr来了解它的原理

C++98方法一:只声明不实现,不让编译器自动生成。

template<class T>
class unique_ptr {
public:
	unique_ptr(T* ptr)
		:_ptr(ptr) {
	}

	~unique_ptr() {
		delete _ptr;
		cout << "delete->" << _ptr << endl;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }

	//C++98方法一:只声明不实现,不让编译器自动生成。
	unique_ptr(const unique_ptr<T>& up);

private:
	T* _ptr;
};

//但这样可能导致别人在类外面实现
template <class T>
unique_ptr<T>::unique_ptr(const unique_ptr<T>& up) {}

C++98方法二:声明为私有

template<class T>
class unique_ptr {
public:
	unique_ptr(T* ptr)
		:_ptr(ptr) {
	}

	~unique_ptr() {
		delete _ptr;
		cout << "delete->" << _ptr << endl;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }

private:
	//C++98方法二:声明为私有
	unique_ptr(const unique_ptr<T>& up);
	unique_ptr<T>& operator=(const unique_ptr<T>& up);
private:
	T* _ptr;
};

C++11

template<class T>
class unique_ptr {
public:
	unique_ptr(T* ptr)
		:_ptr(ptr) {
	}

	~unique_ptr() {
		delete _ptr;
		cout << "delete->" << _ptr << endl;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }

	//C++11
	unique_ptr(const unique_ptr<T>& up) = delete;
	unique_ptr<T>& operator=(const unique_ptr<T>& up) = delete;

private:
	T* _ptr;
};

3.5 std::shared_ptr

C++11中开始提供更靠谱的并且支持拷贝的shared_ptr

std::shared_ptr文档

shared_ptr的原理:是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。例如:比特老师晚上在下班之前都会通知,让最后走的学生记得把门锁下。

  1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
  2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
  4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指针了。
template<class T>
	class shared_ptr {
	public:
		shared_ptr(T* ptr = nullptr)
			:_ptr(ptr)
			, _pcount(new int(1)) {
			//构造时开辟存计数的空间,且将计数置为1
		}
        
        //版本一
		~shared_ptr() {
			if (--(*_pcount) == 0) {
				delete _ptr;
				delete _pcount;
				cout << "delete->" << _ptr << endl;
			}
		}
		shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
			//sp赋值给this,this指向的计数(*_pcount)无论如何都要--
			//不能自己给自己赋值。不仅指相同对象,管理同一资源的不同对象也不可以
			//否则可能出现--(*_pcount) == 0导致自己被释放
			if (_ptr != sp._ptr) {
				if (--(*_pcount) == 0) {
					delete _ptr;
					delete _pcount;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}

		//版本二:复用
		void release() {
			if (--(*_pcount) == 0) {
				delete _ptr;
				delete _pcount;
				//cout << "delete->" << _ptr << endl;
			}
		}
		~shared_ptr() { release(); }
		shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
			if (_ptr != sp._ptr) {
				release();
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				++(*_pcount);
			}
			return *this;
		}

		shared_ptr(const shared_ptr<T>& sp)
			:_ptr(sp._ptr)
			, _pcount(sp._pcount) {
			++(*_pcount);
		}

		T& operator*() { return *_ptr; }
		T* operator->() { return _ptr; }
		int use_count() const { return *_pcount; }
		T* get() const { return _ptr; }
	private:
		T* _ptr;
		//int _count;//不可以,智能指针拷贝后两个对象的_count不同步
		//static int _count;//不可以,如果两个智能指针管理两个资源,_count的统计就乱了
		int* _pcount;//去堆开辟空间存计数
	};

std::shared_ptr 的循环引用
该方式可能导致new失败后抛异常无法释放
struct ListNode {
	int val;
	ListNode* next;
	ListNode* prev;
};
void test_shared_ptr2() {
	
	ListNode* n1 = new ListNode;
	ListNode* n2 = new ListNode;
	n1->next = n2;
	n2->prev = n1;
}

循环引用

struct ListNode {
	int val;
	////节点链接时智能指针和节点指针类型不匹配
	//ListNode* next;
	//ListNode* prev;
	shared_ptr<ListNode> next;
	shared_ptr<ListNode> prev;

	//如果节点被智能指针释放会调用析构函数
	~ListNode() { cout << "~ListNode()" << endl; }
};
void test_shared_ptr2() {
	//用智能指针管理,避免抛异常后无法释放
	shared_ptr<ListNode> n1 = new ListNode;
	shared_ptr<ListNode> n2 = new ListNode;
	
	n1->next = n2;
	n2->prev = n1;
}

循环引用导致内存泄漏

n1 的引用计数 = 2(n1 本身 + n2->prev)
n2 的引用计数 = 2(n2 本身 + n1->next)
n2先析构。n2的引用计数2 → 1(因为n1->next仍然持有ListNode2)
n2的引用计数 = 1,所以 ListNode2 不会释放。
n1后析构。n1的引用计数2 → 1(因为n2->prev仍然持有ListNode1)
n1的引用计数 = 1,所以 ListNode1 不会释放。
最终,n1和n2被销毁了,但ListNode1被n2->prev持有;ListNode2被n1->next持有
 

解决方案:在引用计数的场景下,把节点中的_prev和_next改成weak_ptr就可以了
原理就是,n1->_next = n2;和n2->_prev = n1;时weak_ptr的_next和_prev不会增加node1和node2的引用计数。

template<class T>
class shared_ptr {
public:
	shared_ptr(T* ptr = nullptr)
		:_ptr(ptr)
		, _pcount(new int(1)) {
		//构造时开辟存计数的空间,且将计数置为1
	}

	void release() {
		if (--(*_pcount) == 0) {
			delete _ptr;
			delete _pcount;
			//cout << "delete->" << _ptr << endl;
		}
	}
	~shared_ptr() { release(); }
	shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
		if (_ptr != sp._ptr) {
			release();
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			++(*_pcount);
		}
		return *this;
	}

	shared_ptr(const shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _pcount(sp._pcount) {
		++(*_pcount);
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
	int use_count() const { return *_pcount; }
	T* get() const { return _ptr; }
private:
	T* _ptr;
	int* _pcount;//去堆开辟空间存计数
};

template<class T>
class weak_ptr {
public:
	//当执行 new ListNode 时:先分配内存。
	//然后调用 ListNode 的构造函数(隐式生成的默认构造函数)。
	//ListNode 的默认构造函数会调用 next 和 prev 的默认构造函数(因为它们是成员变量)。
	//如果 weak_ptr 没有默认构造函数,ListNode 的默认构造会失败。
	weak_ptr()
		:_ptr(nullptr) {
	}

	weak_ptr(const shared_ptr<T>& sp)
		:_ptr(sp.get()) {
	}

	weak_ptr<T>& operator=(const shared_ptr<T>& sp) {
		_ptr = sp.get();
		return *this;
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
private:
	T* _ptr;
};

上面的示例中都是new单个对象,用delete销毁。如果new多个对象就需要用delete[]销毁。怎么解决?

template<class T>
struct DelArray {
	void operator()(T* ptr) { delete[] ptr; }
};
void test_shared_ptr3() {
	//shared_ptr<ListNode> sp1(new ListNode[10]);
	//new[] 需要delete[],但shared_ptr是delete

	bit::shared_ptr<ListNode> sp1(new ListNode[3], DelArray<ListNode>());//仿函数
	bit::shared_ptr<ListNode> sp2(new ListNode[3], [](ListNode* ptr) {delete[] ptr; });//lambda
	bit::shared_ptr<FILE> sp3(fopen("Smart Pointers.cpp", "r"), [](FILE* ptr) {fclose(ptr); });//lambda
	bit::shared_ptr<ListNode> sp4(new ListNode);
}

定制删除器

template<class T>
class shared_ptr {
public:
	shared_ptr(T* ptr = nullptr)
		:_ptr(ptr)
		, _pcount(new int(1)) {
	}

	template<class D>
	shared_ptr(T* ptr, D del)
		: _ptr(ptr)
		, _pcount(new int(1))
		, _del(del) {
	}
	//function<void(T*)> _del;
	//参数 D 的本质:它是一个"释放资源的方式",可以处理单个对象或多个对象(比如数组的 delete[])
	//这个释放方式可以是:仿函数、Lambda 表达式、普通函数指针、其他任何可调用实体(总之是个可调用对象)
	//function 的作用:作为通用的包装器,统一存储这些不同类型的可调用对象

	void release() {
		if (--(*_pcount) == 0) {
			//仿函数和lambda都是可调用对象
			_del(_ptr);
			delete _pcount;
			//cout << "delete->" << _ptr << endl;
		}
	}
	~shared_ptr() { release(); }
	shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
		if (_ptr != sp._ptr) {
			release();
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			++(*_pcount);
		}
		return *this;
	}

	shared_ptr(const shared_ptr<T>& sp)
		:_ptr(sp._ptr)
		, _pcount(sp._pcount) {
		++(*_pcount);
	}

	T& operator*() { return *_ptr; }
	T* operator->() { return _ptr; }
	int use_count() const { return *_pcount; }
	T* get() const { return _ptr; }
private:
	T* _ptr;
	int* _pcount;//去堆开辟空间存计数
	//D _del;//不可行,D是构造函数的模板参数,不是整个类的
	function<void(T*)> _del = [](T* ptr) {delete ptr; };
	//给缺省值的原因:如果使用这个智能指针管理资源,且该资源没有传删除器时调用的是默认构造函数。
	//如果不初始化_del,那么析构时_del为空就报错
};

第四章:C++11和boost中智能指针的关系

  1. C++ 98 中产生了第一个智能指针auto_ptr.
  2. C++ boost给出了更实用的scoped_ptr和shared_ptr和weak_ptr.
  3. C++ TR1,引入了shared_ptr等。不过注意的是TR1并不是标准版。
  4. C++ 11,引入了unique_ptr和shared_ptr和weak_ptr。需要注意的是unique_ptr对应boost的scoped_ptr。并且这些智能指针的实现原理是参考boost中的实现的。

作业

1. 下面关于内存泄漏的说法正确的是()

A.如果对程序影响不是很大的情况下,泄漏一两个字节不是很重要
B.内存没有释放时,进程在销毁的时候会统一回收,不用担心
C.内存泄漏不一定会对系统马上造成影响,可以不着急进行处理
D.写代码时要有良好的编码规范,万一发生内存泄漏要及时处理

答案:D
A:错误,一两个字节不处理时可能会因小失大,很多个两字节,就是很大的一块内存空间
B:错误,虽然进程退出时会回收,但是进程为退出时可能会影响程序性能甚至会导致崩溃
C:错误,只要发现了就要及时处理,否则,说不定什么时候程序就会崩溃
D:正确,内存泄漏最好不要发生,万一发生了一定要及时处理

2. 下面那个说法可以表示资源泄漏()

A.从商店买东西
B.借钱不还
C.买房子交首付
D.办信用卡

答案:B
从系统中动态申请的资源,一定要记着及时归还,否则别人可能就使用不了,或者申请失败。
就像借钱一样,有借有还再借不难

3. 以下那个误操作不属于资源泄漏()

A.打开的文件忘记关闭
B.malloc申请的空间未通过free释放
C.栈上的对象没有通过delete销毁
D.内存泄漏属于资源泄漏的一种,但资源泄漏不仅仅是内存泄漏

答案:C
A:属于,打开的文件用完时一定要关闭
B:属于,堆上申请的空间,需要用户显式的释放
C:不属于,栈上的对象不需要释放,函数结束时编译器会自动释放
D:正确,资源泄漏包含的比较广泛,比如文件未关闭、套接字为关闭等

4. 关于RAII下面说法错误的是()

A.RAII的实现方式就是在构造函数中将资源初始化,在析构函数中将资源清理掉
B.RAII方式管理资源,可以有效避免资源泄漏问题
C.所有智能指针都借助RAII的思想管理资源
D.RAII方式管理锁,有些场景下可以有效避免死锁问题

答案:C
A:正确
B:正确
C:错误,weak_ptr不能单独管理资源,必须配合shared_ptr一块使用,解决shared_ptr中存在的循环引用问题
D:正确

5. 下面关于weak_ptr的说法错误的是()

A.weak_ptr与shread_ptr的实现方式类似,都是通过引用计数的方式实现的
B.weak_ptr的对象可以独立管理资源
C.weak_ptr的唯一作用就是解决shared_ptr中存在的循环引用问题
D.weak_ptr一般情况下都用不到

答案:B
A:正确,weak_ptr和shared_ptr都是通过引用计数实现,但是在底层还是有区别的
B:错误,weak_ptr不能单独管理资源,因为其给出的最主要的原因是配合shared_ptr解决其循环引用问题
C:正确,处理解决shared_ptr的循环引用问题外,别无它用
D:正确

6. 下面关于shared_ptr说法错误的是 ( )

A.shared_ptr是C++11才正式提出来的
B.shared_ptr对象之间可以共享资源
C.shared_ptr可以应用于任何场景
D.shared_ptr是借助引用计数的方式实现的

答案:C
A:正确
B:正确,参考shared_ptr的实现原理
C:错误,有些场景下shared_ptr可能会造成循环引用,必须与weak_ptr配合使用
D:正确

7. 下面关于unique_ptr说法错误的是()

A.unique_ptr是C++11才正式提出的
B.unique_ptr可以管理一段连续空间
C.unique_ptr不能使用其拷贝构造函数
D.unique_ptr的对象之间不能相互赋值

答案:B
A:正确
B:错误,C++11中提供的智能指针都只能管理单个对象的资源,没有提供管理一段空间资源的智能指针
C:正确,因为unique_ptr中已经将拷贝构造函数和赋值运算符重载delete了
D:正确,原因同C

8. 下面关于auto_ptr的说法错误的是()

A.auto_ptr智能指针是在C++98版本中已经存在的
B.auto_ptr的多个对象之间,不能共享资源
C.auto_ptr的实现原理是资源的转移
D.auto_ptr完全可以正常使用

答案:D
A:正确
B:正确,因为auto_ptr采用资源管理权转移的方式实现的,比如:用ap1拷贝构造ap2时,ap1中的资源会转移给ap2,而ap1与资源断开联系
C:正确
D:错误,可以使用,但是不建议用,因为有缺陷,标准委员会建议:什么情况下都不要使用auto_ptr
 

【单片机】STM32F103C8T6 最小系统板原理图 STM32F103C8T6是一款基于ARM Cortex-M3内核的32位微控制器,由STMicroelectronics(ST)公司生产。它是STMicroelectronics的STM32系列微控制器中的一员,被广泛应用于嵌入式系统和电子设备中。LQFP48封装(Low-profile Quad Flat Package,48引脚)SRAM(静态随机访问存储器):20 KB。支持JTAG调试和编程接口(可选)多个通用输入/输出口(GPIO)USB接口(用于USB设备模式)内置调试和编程接口(SWD) 阅读详情

相关推荐

即插即用!5分钟为你的SNN模型添加频谱注意力(DCT-SA模块实战)

本文介绍了如何为脉冲神经网络(SNN)快速集成即插即用的DCT-SA频谱注意力模块。该模块利用离散余弦变换(DCT)在频率域自适应加权特征,能有效提升模型对纹理、边缘的感知能力,并在CIFAR10-DVS等数据集上实现分类精度提升与脉冲发放率下降。文章以SpikingJelly框架和ResNet19为例,提供了详细的代码实现、集成步骤及参数调优实战指南。

kotlin6android的博客 609

[cpp进阶]C++智能指针

智能指针运用了RAII的思想。RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。

weixin_53027918的博客 2023

离散数学期末考试试卷(两套)-熟悉题型

3.设集合A={a,b,c,d}上有自反关系R={,,,,},对称关系S={,,,}。6.设集合A={1,2,3},B={u,v,w},C={a,b,c},f是集合A到集合B上的映射,g是集合B到集合C上的映射,f={, , },g={},则复合函数g。5. 设集合A={a,b,c,d,e},下列选项中哪一个集合不是A的划分( )。

muse3159546973的博客 6956

[C++] 智能指针 进阶

[C++] 智能指针 进阶 在很久之前我们探讨了智能指针的浅显认识,接下来会更加深入,从源码角度认识智能指针,从而了解智能指针的设计原理,并应用到以后的工作项目中。本文将会按照C++智能指针的发展历史,回顾智能指针的各个版本的设计。后半部分将会模拟实现最常考的shared_ptr的功能。

石墨博客 1250

解密电商大促背后的智慧:LSTM与ARIMA模型的双剑合璧

举个例子,如果某东发现某款新推出的电子产品在促销前夕搜索量突然暴涨,虽然这个产品没有过去的销售记录,但LSTM模型可以结合用户对类似产品的行为模式、实时的市场反馈,迅速捕捉到这些变化,并预测这款产品在大促期间的需求会急剧上升。想象一下,如果预测不准确,备货不足,商品很快就卖光了,大量用户可能在促销期间买不到想要的商品,这不仅让用户失望,还会影响某东的品牌形象。这种情况就像我们看一部很长的电视剧,看得越久,前面的情节可能就越来越模糊,到最后有些关键的情节细节都忘了,影响了对整个剧情的理解。

小蒋聊技术 2090

全国大学校园网—拓扑图欣赏

全国大学网络拓扑图(一百张) 典型十张 1、 中央财经大学 2、国防科技大学 3、济南大学 4、西安石油大学 5、南通大学IPV6网络 6、中国矿业大学 7、青海师范大学 8、内蒙古科技大学 9、三峡大学 10、中共江苏省党校 剩余90张 点赞、评论获取 ...

LiBai'S BLOG 5万+

C++进阶——C++11_智能指针

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存,一般是忘记释放或者发生异常释放程序未能执行导致的。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏的危害普通程序运行一会就结束了出现内存泄漏问题也不大,进程正常结束,页表的映射关系解除,物理内存也可以释放。长期运行的程序出现内存泄漏影响很大。

博客 | 复习知识点 + 练习 + 最终的领悟 | 全力以赴 1525

(遇到问题)(已解决)word敲入的公式转化为mathtype

https://www.mathtype.cn/wenti/wordgongshi-zhuanhuan.html 现在越来越多的人在文档中编辑公式的时候会选择MathType来编辑,因为它包含有众多的数学符号和模板,编辑公式时非常方便。但是也有一些人在编辑公式时没有使用MathType公式编辑器,直接使用Word中自带的公式编辑器来编辑的。当我们需要要共享一份文件的时候,这种用自带公式编辑器编辑出来的文件,在我们安装有MathType公式编辑器的电脑里打开时,双击公式没有反应,是无法对它们进行修改的.

计算机视觉 1万+

Cpp 进阶:Smart Pointer 智能指针

Cpp 进阶:Smart Pointer 智能指针 文章目录Cpp 进阶:Smart Pointer 智能指针简介参考正文核心目的功能需求C++ 实现智能指针(包装类)全局工厂包装函数测试用对象类测试代码结语 简介 我们都知道 Java 和 C++ 一样,运行时会同时维护一个堆(Heap)空间与栈(Stack)空间。通常局部变量、函数参数等都会存放在栈空间,跟着函数运行周期一起消亡;而 Java 和 C++ 对于堆空间的控制则不太相同: 对于 Java **“万物皆对象”**的设计理念,程序以对象(Ob

超悠閒的博客 512

群晖NAS下docker安装MySql

本文将一步一步讲解如何在群晖NAS的docker中启用一个MySQL容器 , 算是初学者对问题解决的一个记录.

qq_46375248的博客 5976

超分算法 SwinIR: Image Restoration Using Swin Transformer

这篇文章结构比较简单,如果看过Swin-Transformer的话就没什么难点了。作者引入Swin-T结构应用于低级视觉任务,包括图像超分辨率重建、图像去噪、图像压缩伪影去除。网络由一个浅层特征提取模块、深层特征提取模块、重建模块构成。重建模块对不同的任务使用不同的结构。浅层特征提取就是一个3×3的卷积层。深层特征提取是k个RSTB块和一个卷积层构成。RSTB(Res- SwinIR: Image Restoration Using Swin Transformer[ICCV 2021]Abstract1.

qq_45122568的博客 1万+

C++进阶--C++11智能指针

智能指针不是指针,是一个管理指针的类,用来存储指向动态分配对象的指针,负责自动释放动态分配的对象,防止堆内存泄漏。动态分配的资源,交给一个类对象去管理,当类对象生命周期结束时,自动调用析构函数释放资源。RAII是resource acquisition is initialization的缩写,意为“资源获取即初始化”。它是 C++ 之父 Bjarne Stroustrup 提出的设计理念,其核心是把资源和对象的生命周期绑定,对象创建获取资源,对象销毁释放资源。

sushang的博客 6195

超越防抖:索尼CXD5254GG芯片如何重新定义电子影像稳定

索尼CXD5254GG芯片通过融合6轴IMU与图像传感器数据,重新定义了电子影像稳定技术。其核心突破在于实时地平线校正、抑制果冻效应和镜头畸变校正,并搭载智能画质控制器提升画面细节。该芯片适用于广播制作、体育娱乐、安防监控和机器人视觉导航等专业领域,提供开箱即用的优化参数配置,大幅缩短开发周期。CXD5254GG不仅实现稳定成像,更通过姿态感知与智能优化,为专业影像应用提供了完整的稳定解决方案。

致力于lidar应用开发 113

C++进阶-智能指针

什么是内存泄漏:内存泄漏指因为疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,失去了对该段内存的控制,因而造成了内存的浪费。内存泄漏的危害:长期运行的程序出现内存泄漏,影响很大,如操作系统、后台服务等等,出现内存泄漏会导致响应越来越慢,最终卡死。// 1.内存申请了忘记释放// 2.异常安全问题Func();// 这里Func函数抛异常导致 delete[] p3未执行,p3没被释放.

weixin_64423718的博客 1080

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C++学习进阶:C++11|智能指针

这是一篇又臭又长又精华的博客,需要每一个模块认真学习,仔细理解,这一部分也是C++面试常考的内容,那么废话不多说,just do it!

weixin_73234157的博客 1272

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++进阶(9)——智能指针的使用及其原理

本文探讨了智能指针的使用场景及实现原理。文章首先通过一个除零异常导致内存泄漏的例子,说明智能指针的必要性。随后介绍了RAII设计原则和智能指针的基本实现思路,包括auto_ptr、unique_ptr和shared_ptr三种主要类型,重点分析了shared_ptr的引用计数机制及其循环引用问题,并提出了weak_ptr的解决方案。文章还讨论了智能指针的线程安全问题和定制删除器功能,最后简要说明了C++11智能指针与Boost库的关系。

2301_80065652的博客 3330

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++进阶:智能指针

其除了具备智能指针管理资源与指针操作的功能外,对智能指针的拷贝也做了相关的实现,其设计思路为拷贝后,将指针转移,将原有指针悬空。weak_ptr只做链接功能,因为weak_ptr与shared_ptr不是一个类型的智能指针,weak_ptr想要从shared_ptr获取资源只有两个方式,一是被声明为友元,二是为shared_ptr添加get接口,get接口必须使用const修饰this指针。自定义一个双向链表的节点,链表的每个节点都是动态开辟而出的,这里我们采用智能指针的方式去定义与管理。

qq_71806743的博客 1334

【C++进阶】智能指针的使用及其原理

本文介绍了C++智能指针的使用场景、设计思路及标准库实现。主要内容包括: 通过异常处理案例展示内存泄漏问题,说明智能指针的必要性; 提出RAII(资源获取即初始化)设计思想,利用对象生命周期管理资源; 设计简易智能指针类,实现资源自动释放和指针行为模拟; 分析智能指针拷贝问题,对比标准库的auto_ptr、unique_ptr等解决方案; 重点指出auto_ptr存在管理权转移缺陷,建议避免使用。 文章通过代码示例和图示,系统讲解了智能指针如何解决资源泄漏问题,并比较了不同智能指针的实现特点。

Linux、C++、图形软件开发等。不一定每次都能写出完美的代码,但会认真搞懂每一个问题。 7376

C++进阶 智能指针

介绍了C++中的智能指针

小萌新的博客 1142

c++进阶——智能指针

本文介绍了C++智能指针的原理和应用。针对普通指针在异常处理时可能造成的内存泄漏问题,提出了RAII(资源获取即初始化)思想,通过类对象的生命周期自动管理资源释放。文章展示了自定义智能指针的实现示例,并指出其存在的析构匹配问题。同时分析了C++标准库提供的智能指针类型,特别指出c++98的auto_ptr存在被拷贝对象悬空的设计缺陷。智能指针通过自动化资源管理,有效解决了传统指针在异常情况下的内存泄漏问题,是C++中重要的资源管理工具。

2301_79705195的博客 1121

C++进阶之智能指针

RAII(Resource Acquisition Is Initialization)是一种(如内存、文件句柄、网络连接、互斥量等等)的简单技术。,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后。借此,我们实际上把管理一份资源的责任托管给了一个对象。

baobao1767640830的博客 1100

C++进阶——智能指针(C++11)

所以,总的来说,如果我们要用智能指针的话,一般用 shared_ptr 和 weak_ptr 搭配用就可以解决程序因为抛异常而导致执行流乱跳,进而造成内存泄漏等问题了。

m0_73093743的博客 1989

《C++进阶之C++11》【智能指针】(上)

本文介绍了C++中三种常用智能指针:unique_ptr、shared_ptr和weak_ptr。文章通过代码示例演示了各类智能指针的基本用法和适用场景,并强调其基于RAII机制自动管理内存的核心优势。

序属秋秋秋的博客 1329

【C++进阶篇】智能指针

本文深入解析C++智能指针的内存管理机制,重点介绍auto_ptr、unique_ptr和shared_ptr三大智能指针的核心特性与使用场景。auto_ptr因资源转移问题被淘汰,unique_ptr采用独占所有权设计,而shared_ptr通过引用计数实现共享所有权。文章详细剖析shared_ptr的原理,包括堆上动态分配引用计数器的必要性,并通过源码模拟演示其实现机制。特别强调make_shared的性能优势(单次内存分配)及自定义删除器的使用场景,为C++开发者提供全面的智能指针应用指南。

braveact的博客 1449

C++进阶——智能指针

默认选择unique_ptr:明确所有权,高效安全。共享资源用shared_ptr:配合weak_ptr用于观察共享资源。避免手动newdelete:减少内存管理错误。

k42946的博客 1054

C++进阶 —— 智能指针

智能指针,RAII;

NapoleonCoder的博客 1258
上一篇: C++进阶—异常
下一篇: C++进阶—特殊类设计
Awkwardx
博客等级 码龄5年 341粉丝 82原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值