所以我正在设计一个处理大量内存的类,如果在它的构造函数的内存分配过程中出现问题,我想确保它能正确地解开。
下面是我得到的信息:
class foo{
public:
foo(): var1(nullptr), var2(nullptr){
try{
var1 = new int(1);
var2 = new int(2);
}
catch(std::exception &e){
delete var1;
delete var2;
return;
}
//Some other things involving these variables
}
如果我只想在构造器中后面的代码因为bad_alloc异常而导致错误之前停止构造这个对象,那么在catch块中返回这个值对吗?或者catch块在终止时只是取消构造函数?我是不是把整件事搞得太复杂了?
发布于 2017-05-19 15:49:06
我想确保如果在它的构造函数的内存分配过程中出现问题,它会正确地展开。
然后,您必须使您的代码符合“一个类控制一个资源或做一个工作”的思想。
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(new int(1))
, var2(new int(2))
{
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
其他正确的初始化形式:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(std::make_unique<int>(1))
, var2(std::make_unique<int>(2))
{
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
默认值:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
// default constructor now implicit
std::unique_ptr<int> var1 = std::make_unique<int>(1); // unique_ptr only manages a resource
std::unique_ptr<int> var2 = std::make_unique<int>(2); // unique_ptr only manages a resource
};
正确,但习惯用法是令人不快的-冗余初始化:
#include <memory>
// foo has one job - to manage fooness.
// It no longer manages memory resources
class foo
{
public:
foo()
: var1(nullptr)
, var2(nullptr)
{
var1 = std::make_unique<int>(1);
var2 = std::make_unique<int>(2);
}
std::unique_ptr<int> var1; // unique_ptr only manages a resource
std::unique_ptr<int> var2; // unique_ptr only manages a resource
};
这里有一种不用组合就能做到的方法。注意所有额外的复杂性,而不会获得任何收益:
#include <memory>
// foo now has two jobs - to manage fooness, and to manage resources.
// This adds un-necessary complication, bugs and maintenance overhead
class foo
{
public:
foo()
: var1(nullptr)
, var2(nullptr)
{
var1 = new int(1);
var2 = new int(2);
}
foo(const foo& other)
: var1(nullptr)
, var2(nullptr)
{
if (other.var1) {
var1 = new int(*(other.var1));
}
if (other.var2) {
var2 = new int(*(other.var2));
}
}
foo(foo&& other) noexcept
: var1(other.var1)
, var2(other.var2)
{
other.var1 = nullptr;
other.var2 = nullptr;
}
foo& operator=(const foo& other)
{
foo tmp(other);
std::swap(var1, tmp.var1);
std::swap(var2, tmp.var2);
return *this;
}
foo& operator=(foo&& other) noexcept
{
foo tmp(std::move(other));
std::swap(var1, tmp.var1);
std::swap(var2, tmp.var2);
return *this;
}
~foo() noexcept
{
delete var1;
delete var2;
}
int* var1; // doesn't manage anything
int* var2; // doesn't manage anything
};
发布于 2017-05-19 15:51:30
您应该检查一下智能指针:std::unique_ptr
(在本例中很有用)和std::shared_ptr
/std::weak_ptr
(对于您的示例来说,类型不是正确的,但很好知道)。
只要你没有重新实现某种类型的智能指针,使用它们而不是动态分配,它将为你省去一些麻烦(即使你的例子是正确的,不会泄漏,只要析构函数是正确的)。
您应该抛出一个异常,而不是返回:应该通知调用者构造失败(如果分配失败意味着构造函数失败)。RAII意味着对象永远不应该处于无效状态。
https://stackoverflow.com/questions/44064194
复制相似问题