背景:
一般去搜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)