我真是孤陋寡闻了,今天才知道NULL指针是可以直接delete的

vipcxj 2014-01-02 08:13:02
以前一直以为得先判断非空再delete,貌似当初学的时候老师给的示例代码也是先判空滴,还记得有个曾被广泛使用的宏
#define SAFE_DELETE(p) {if (p) delete p;}
话说C++是什么时候开始可以安全地delete空指针了?或者从c++发明出来就一直能安全delete空指针?
还有别人和我这样误解了N久的吗?
...全文
2092 68 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
68 条回复
切换为时间正序
请发表友善的回复…
发表回复
zeloas 2015-09-06
  • 打赏
  • 举报
回复
没啥好说的VC++ 6.0的时代,delete不是能delete空指针的 因为c++标准还没有定好的说
jiht594 2015-09-06
  • 打赏
  • 举报
回复
SAFE_DELETE(p); SAFE_DELETE(p); SAFE_DELETE(p);
「已注销」 2015-09-06
  • 打赏
  • 举报
回复
你们真是多虑了,释放 NULL 指针还用判断吗?当然,不用判断不代表不需要判断。稍微想想都知道,标准 C 库函数的 free 或 delete 内部肯定已经判断过了,人家写库函数或编译器的人不会连这都考虑不周到。这种我经常不判断的,其他的比如 CloseHandle、GlobalFree、LocalFree 只要不是野指针,是否为空,仅仅是释放的话判断都是多余的。当然,如果判断有写入的话还是需要判断。而如果仅仅是判断是否释放,如这样的代码: if (p != NULL) { free(p); } 放心大胆的直接写 free(p) 吧!从 free 到 HeapFree 再到 RtlFreeHeap,CRT 以及系统一定会层层帮你把关的,还少你这一层判断吗?
daniel-du 2015-09-04
  • 打赏
  • 举报
回复
我见到的SafeDelete,一般都是这样的, if(p)p->Release(); 如果单单是为了Delete p,就没有意义了。正如楼上说的,essential c++里都提到过了。
vipcxj 2014-01-05
  • 打赏
  • 举报
回复
引用 63 楼 lm_whales 的回复:
CSDN 里有一个帖子里,SAFE_DELETE 是这样定义的: #define SAFE_DELETE(p) { delete p; p = NULL;} 这样可以保证,即使 delete p;了,p 也不是野指针。 也就这点安全。 #define SAFE_DELETE(p) {if (p) delete p;} 一般来说,如果抠的紧的话,还带来效率的损失。 因为定义指针,是为了应用,而不是让他 一直为NULL。 所以,p!=NULL 才是,那%80的情况,p == NULL ,才是无关紧要的 %20;
boost里也有个SAFE_DELETE,那个也没有什么对空指针的判断,不过那个safe是对于不完全类型的角度来说的,当时我就有点奇怪为什么boost这么专业的库既然都说SAFE了都不顺便判断一下空,直到后来看到有个源代码里析构函数是直接delete的,才发现不对,自己试了之后才知道,直接delete空指针完全木有问题。
lm_whales 2014-01-05
  • 打赏
  • 举报
回复
CSDN 里有一个帖子里,SAFE_DELETE 是这样定义的: #define SAFE_DELETE(p) { delete p; p = NULL;} 这样可以保证,即使 delete p;了,p 也不是野指针。 也就这点安全。 #define SAFE_DELETE(p) {if (p) delete p;} 一般来说,如果抠的紧的话,还带来效率的损失。 因为定义指针,是为了应用,而不是让他 一直为NULL。 所以,p!=NULL 才是,那%80的情况,p == NULL ,才是无关紧要的 %20;
lm_whales 2014-01-05
  • 打赏
  • 举报
回复
Essential C++ 里面,专门提到 if (p) delete p; 的if 是多此一举的。
Inhibitory 2014-01-04
  • 打赏
  • 举报
回复
貌似当初学的时候老师给的示例代码也是先判空滴,还记得有个曾被广泛使用的宏 #define SAFE_DELETE(p) {if (p) delete p;} 竟然用了safe,这是在打脸么
版主大哥 2014-01-04
  • 打赏
  • 举报
回复
引用 43 楼 zhao4zhong1 的回复:
为什么不直接看Linux下free和delete的源代码呢?
free和delete的源代码中有个 if (p == NULL) return; 是不是一目了然了?还什么标准的....这才是真理
mujiok2003 2014-01-04
  • 打赏
  • 举报
回复
引用 38 楼 vipcxj 的回复:

#include <boost/timer/timer.hpp>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	namespace timer = boost::timer;
	const long long iterNum = 1000000;
	int *p = NULL;
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			if (p)
			{
				delete p;
			}
		}
	}
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			delete p;
		}
	}

	system("pause");

	return 0;
}
关于效率问题,我专门试了下,不过我这个测试代码貌似有问题,里面是两个循环,一个是直接delete,一个是先判断再delete,结果那个循环在前面,哪个速度就快很多,我估计和cpu的cashe命中率有关系。但通过交换2个循环的顺序,还是可以大致判断出先判断的那个仅对于delete空指针来说要快那么一点点。但是我还测试了delete非空的有效指针,它的效率比delete空指针低几百倍,换句话说先判空再delete在实际应用中提升的效率估计微乎其微,甚至木有~ 其实从那个宏的名字SAFE_DELETE来看就知道创出这个宏的人也不是为了什么效率,而是想要安全性,但事实上这个宏并不能提高任何安全性~
用下面的方法试验一下.
#include <chrono>
#include <iostream>

#if 1
#define mydelete(p) if(p) delete p
#else
#define mydelete(p)  delete p
#endif
int main()
{
	auto start = std::chrono::high_resolution_clock::now();
	int* p = nullptr;
	for (int i = 0; i < 90000; i++)
	{
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
		mydelete(p);
	}
	
	auto end = std::chrono::high_resolution_clock::now() - start;

	std::cout << end.count() << std::endl;

}
mujiok2003 2014-01-04
  • 打赏
  • 举报
回复
引用 38 楼 vipcxj 的回复:

#include <boost/timer/timer.hpp>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	namespace timer = boost::timer;
	const long long iterNum = 1000000;
	int *p = NULL;
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			if (p)
			{
				delete p;
			}
		}
	}
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			delete p;
		}
	}

	system("pause");

	return 0;
}
关于效率问题,我专门试了下,不过我这个测试代码貌似有问题,里面是两个循环,一个是直接delete,一个是先判断再delete,结果那个循环在前面,哪个速度就快很多,我估计和cpu的cashe命中率有关系。但通过交换2个循环的顺序,还是可以大致判断出先判断的那个仅对于delete空指针来说要快那么一点点。但是我还测试了delete非空的有效指针,它的效率比delete空指针低几百倍,换句话说先判空再delete在实际应用中提升的效率估计微乎其微,甚至木有~ 其实从那个宏的名字SAFE_DELETE来看就知道创出这个宏的人也不是为了什么效率,而是想要安全性,但事实上这个宏并不能提高任何安全性~
循环占了大部分的时间,测试结果不可信.
mujiok2003 2014-01-04
  • 打赏
  • 举报
回复
引用 53 楼 fyzqzpd 的回复:
其实if(p)的真正用途是节省CPU,如果是空指针就不用调用delete了。在每秒钟上千次的调用下,可以加速很多呢!
终于有正解了!
bravery36 2014-01-04
  • 打赏
  • 举报
回复
我印象中free(NULL)是会出事的,不知道现在的编译器是否有改良,delete(NULL)一直很安全。
zhao1zhong6 2014-01-04
  • 打赏
  • 举报
回复
其实if(p)的真正用途是节省CPU,如果是空指针就不用调用delete了。在每秒钟上千次的调用下,可以加速很多呢!
碼上道 2014-01-04
  • 打赏
  • 举报
回复
#define SAFE_DELETE(p) {if (p) delete p;} 效率上有些影响,毕竟要少一个函数调用。
vipcxj 2014-01-04
  • 打赏
  • 举报
回复
引用 58 楼 xihu1364 的回复:
[quote=引用 43 楼 zhao4zhong1 的回复:] 为什么不直接看Linux下free和delete的源代码呢?
free和delete的源代码中有个 if (p == NULL) return; 是不是一目了然了?还什么标准的....这才是真理[/quote] 因为不同平台free和delete的实现甚至有可能是不同的,难道你把每个平台的源码都看一遍。一般来说C++的实现只要符合了标准,标准没提到的细节,各个版本编译器和它们的运行时库都有自己的一套实现。当然你非要说不少编译器不按标准来我也没办法~
MARS用了8年 2014-01-03
  • 打赏
  • 举报
回复
鸠摩(马智) 2014-01-03
  • 打赏
  • 举报
回复
我也不知道,学习了
vipcxj 2014-01-03
  • 打赏
  • 举报
回复

#include <boost/timer/timer.hpp>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
	namespace timer = boost::timer;
	const long long iterNum = 1000000;
	int *p = NULL;
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			if (p)
			{
				delete p;
			}
		}
	}
	{
		timer::auto_cpu_timer atimer;
		for (long long i = 0; i < iterNum; i++)
		{
			//p = new int(3);
			delete p;
		}
	}

	system("pause");

	return 0;
}
关于效率问题,我专门试了下,不过我这个测试代码貌似有问题,里面是两个循环,一个是直接delete,一个是先判断再delete,结果那个循环在前面,哪个速度就快很多,我估计和cpu的cashe命中率有关系。但通过交换2个循环的顺序,还是可以大致判断出先判断的那个仅对于delete空指针来说要快那么一点点。但是我还测试了delete非空的有效指针,它的效率比delete空指针低几百倍,换句话说先判空再delete在实际应用中提升的效率估计微乎其微,甚至木有~ 其实从那个宏的名字SAFE_DELETE来看就知道创出这个宏的人也不是为了什么效率,而是想要安全性,但事实上这个宏并不能提高任何安全性~
luotuo44 2014-01-03
  • 打赏
  • 举报
回复
引用 43 楼 zhao4zhong1 的回复:
为什么不直接看Linux下free和delete的源代码呢?
有道理
加载更多回复(46)

65,186

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧