CPP make_unique 与new区别?

248 阅读2分钟

 背景:

一般去搜make_unique作用,大多数都是说内存安全,及书写简洁。内存安全指的是当一个函数有多个unique_ptr参数需要实例化调用时,但有参数构造失败时,其他已经完成构造的参数无法析构,无法释放内存。如下面函数:

void doSomething(std::unique_ptr<Diff_New_Make_unique> a,
	std::unique_ptr<Diff_New_Make_unique> b)
{
	std::cout << (*a).num << std::endl;
	std::cout << (*b).num << std::endl;
}
		doSomething(std::unique_ptr<Diff_New_Make_unique>(new Diff_New_Make_unique(false, 1))
			, std::unique_ptr<Diff_New_Make_unique>(new Diff_New_Make_unique(true, 2)));
//出现异常后,都无法调用Diff_New_Make_unique的析构函数。 在C17前会出现无法delete内存问题。
		doSomething(std::make_unique<Diff_New_Make_unique>(false,1)
			, std::make_unique<Diff_New_Make_unique>(true,2));
//正常delete , 可以调用正常实例化的对象的析构函数

结论:

在C17之前,不使用make_unique构造函数参数,当构造参数某个参数构造出现异常时已经完成构造的参数,确实会出现无法调用delete导致内存泄露问题。在C17及之后就没有出现无法delete的情况了。但是无论是C几,不使用make_unique在某个参数出现异常后,已经完成构造的参数都无法调用析构函数。

代码如下:

#pragma region make_unique与new区别
void* operator new(std::size_t size)
{
	auto p = std::malloc(size);
	std::cout << "new({" << size << "}) at {" << p << "}" << std::endl;
	return p;
}

void operator delete(void* p)
{
	std::cout << "delete({" << p << "})" << std::endl;
	std::free(p);
}

class Diff_New_Make_unique
{
private:
	
	//std::unique_ptr<int> num;

public:
	int num;
	Diff_New_Make_unique(bool isBuild, int num);
	~Diff_New_Make_unique();

};

Diff_New_Make_unique::Diff_New_Make_unique(bool isBuild, int num)
{
	std::cout << "Construction" << num << std::endl;
	this->num = num;
	//this->num = new int(num);
	//this->num = std::move(std::unique_ptr<int>(new int(num)));
	if (!isBuild)
		throw "some error";
}

Diff_New_Make_unique::~Diff_New_Make_unique()
{
	std::cout << "Destruct" <<num<< std::endl;
	//delete num;
}

void doSomething(std::unique_ptr<Diff_New_Make_unique> a,
	std::unique_ptr<Diff_New_Make_unique> b)
{
	std::cout << (*a).num << std::endl;
	std::cout << (*b).num << std::endl;
}
#pragma endregion

int main()
{
	std::cout << "Hello World!\n";
#pragma region make_unique与new区别

	try
	{
		doSomething(std::unique_ptr<Diff_New_Make_unique>(new Diff_New_Make_unique(false, 1))
			, std::unique_ptr<Diff_New_Make_unique>(new Diff_New_Make_unique(true, 2)));

		//doSomething(std::make_unique<Diff_New_Make_unique>(true,1)
		//	, std::make_unique<Diff_New_Make_unique>(false,2));


	}
	catch (...)
	{
		std::cout << "Exception" << std::endl;
	}
#pragma endregion

效果:

 new : 

(C14)

(C17)

make_unique:

(C14)

(C17)