在C++分配内存时,如何让代码更健壮

起因

前一段时间在更新.Net Runtime源码时,发现CLR的源码我不认识的用法(毕竟是做C#的,C++的简单用法能看懂),看到nothrow的用法,便去查询了一下是怎么回事.
在C++分配资源失败时,应该用std::nothrow,让代码健壮
nothrow是在分配资源(包括内存)失败时,可以对返回的值判断并进行处理,正常这种情况下,应该使用异常处理(try catch),在没有内存可分配时,使用异常处理也无济于事.

在C语言中,分配资源时

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char* argv[])
{

	char* str = (char*)malloc(sizeof(char) * 128); 
	if (str == NULL)  //如果str指向NULL,代表分配内存失败
	{
		printf("申请内存失败,没有可用的内存");
		exit(1);
	}

	return 0;
}

在C++ 分配资源使用nothrow

#include <iostream>

using namespace std;


class Person
{
public:
	Person()
	{
		cout << "构造函数" << endl;
	}

	~Person()
	{
		cout << "析构函数" << endl;
	}
	static void* operator new (size_t size)
	{
		cout << "局部 new " << endl;
		Person* p = ::new Person;      //引用全局的new,这里还是会调用一次构造函数
		return p;
	}
	static void operator delete(void* p)
	{
		cout << "局部 delete " << endl;
		::delete p;
	}
};

int main(int argc, char* argv[])
{

	Person* p1 = ::new(std::nothrow) Person;  
	if (!p1)  //在分配资源后,判断资源是否分配成功
	{
		cout << "申请内存失败,没有可用的内存" << endl;
		exit(1);
	}

	return 0;
}

nothrow在标准库下,nothrow是一个结构体.具体可以看文档:operator new

//这是使用VS转定义查看的
#ifndef __NOTHROW_T_DEFINED
#define __NOTHROW_T_DEFINED
    namespace std
    {
        struct nothrow_t {
            explicit nothrow_t() = default;
        };

        #ifdef _CRT_ENABLE_SELECTANY_NOTHROW
            extern __declspec(selectany) nothrow_t const nothrow;
        #else
            extern nothrow_t const nothrow;
        #endif
    }
#endif

在@0xc0000082(头条号)的帮助下,看到在new的时候加上nothrow,只是调用new带nothrow的重载方法.

//默认调用new
_NODISCARD _Ret_notnull_ _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR
void* __CRTDECL operator new(
    size_t _Size
    );
//加nothrow的new重载 noexcept等同noexcept(true),不抛出异常
_NODISCARD _Ret_maybenull_ _Success_(return != NULL) _Post_writable_byte_size_(_Size) _VCRT_ALLOCATOR
void* __CRTDECL operator new(
    size_t _Size,
    ::std::nothrow_t const&
    ) noexcept;
秋风 2021-09-13