如何使用带有构造函数的初始化列表进行异常处理?
How to use exception handling with initializer-list with constructor?
我曾经通过 Constructor 使用 initialization list
,一切都很顺利。但是现在我的 class.
中需要一些 exception handling
下面是一些示例代码:
1- 没有异常处理
class CVector{
public:
CVector(const int);
protected:
int* pInt;
int size;
};
CVector::CVector(const int sz) :
pInt{ new int[sz]}, size{ sz}{
}
上面的构造函数不检查是否传递了无效的大小,或者new
失败...
现在我编辑了构造函数来处理异常:
2- 有异常处理:
CVector::CVector(const int sz){
size = sz;
if(size <=0 )
throw; // some exception object
pInt = new int[sz];
if(nullptr == pInt)
throw; // some memory exception
}
- 现在的问题:它们是排他性的吗? - 我的意思是如何通过构造函数将异常处理与初始化列表混合?
1) 将大小验证检查提取到一个单独的静态方法中(很可能无论如何都会被重用); 2) 不再需要检查 new
返回的值,如果失败则抛出 std::bad_alloc
异常。所以你的代码可以变成这样:
class CVector{
public:
CVector(const int);
static int Validate_Size(int const size);
protected:
int * m_pInt;
int m_size;
};
int CVector::Validate_Size(int const size)
{
if(size <= 0)
{
throw std::invalid_argument{};
}
return(size);
}
CVector::CVector(const int size)
: m_pInt{new int[Validate_Size(size)]}
, m_size{size}
{}
乍一看,不清楚您是否打算让 CVector 负责拥有整数的动态。你可能会。
几乎毫无疑问,您会希望程序中的每个 class 最多管理一个动态资源(例如分配的内存)。这是因为当有多个资源时,工作变得繁重。
在您的例子中,资源是 int 数组。因此,让我们将责任赋予 CVector,并使用 unique_ptr
:
来管理该责任
#include <memory>
#include <cstddef>
#include <algorithm>
struct CVector
{
CVector(std::size_t initial_size)
: data_ { std::make_unique<int[]>(initial_size) }
, size_ { initial_size }
{
}
// we will probably want the vector to be copyable
CVector(CVector const& other)
: data_ { std::make_unique<int[]>(other.size_) }
, size_ { other.size_ }
{
auto first = other.data_.get();
auto last = first + other.size_;
std::copy(first, last, data_.get());
}
// move consruction is defaultable because it is enabled for
// unique_ptr
CVector(CVector&&) = default;
// assignment
CVector& operator=(CVector const& other)
{
auto temp = other;
swap(temp);
return *this;
}
CVector& operator=(CVector&& other) = default;
// no need for a destructor. unique_ptr takes care of it
void swap(CVector& other) noexcept
{
using std::swap;
swap(data_, other.data_);
swap(size_, other.size_);
}
private:
// defer memory ownership to a class built for the job.
std::unique_ptr<int[]> data_;
std::size_t size_;
};
我曾经通过 Constructor 使用 initialization list
,一切都很顺利。但是现在我的 class.
exception handling
下面是一些示例代码:
1- 没有异常处理
class CVector{
public:
CVector(const int);
protected:
int* pInt;
int size;
};
CVector::CVector(const int sz) :
pInt{ new int[sz]}, size{ sz}{
}
上面的构造函数不检查是否传递了无效的大小,或者new
失败...
现在我编辑了构造函数来处理异常:
2- 有异常处理:
CVector::CVector(const int sz){
size = sz;
if(size <=0 )
throw; // some exception object
pInt = new int[sz];
if(nullptr == pInt)
throw; // some memory exception
}
- 现在的问题:它们是排他性的吗? - 我的意思是如何通过构造函数将异常处理与初始化列表混合?
1) 将大小验证检查提取到一个单独的静态方法中(很可能无论如何都会被重用); 2) 不再需要检查 new
返回的值,如果失败则抛出 std::bad_alloc
异常。所以你的代码可以变成这样:
class CVector{
public:
CVector(const int);
static int Validate_Size(int const size);
protected:
int * m_pInt;
int m_size;
};
int CVector::Validate_Size(int const size)
{
if(size <= 0)
{
throw std::invalid_argument{};
}
return(size);
}
CVector::CVector(const int size)
: m_pInt{new int[Validate_Size(size)]}
, m_size{size}
{}
乍一看,不清楚您是否打算让 CVector 负责拥有整数的动态。你可能会。
几乎毫无疑问,您会希望程序中的每个 class 最多管理一个动态资源(例如分配的内存)。这是因为当有多个资源时,工作变得繁重。
在您的例子中,资源是 int 数组。因此,让我们将责任赋予 CVector,并使用 unique_ptr
:
#include <memory>
#include <cstddef>
#include <algorithm>
struct CVector
{
CVector(std::size_t initial_size)
: data_ { std::make_unique<int[]>(initial_size) }
, size_ { initial_size }
{
}
// we will probably want the vector to be copyable
CVector(CVector const& other)
: data_ { std::make_unique<int[]>(other.size_) }
, size_ { other.size_ }
{
auto first = other.data_.get();
auto last = first + other.size_;
std::copy(first, last, data_.get());
}
// move consruction is defaultable because it is enabled for
// unique_ptr
CVector(CVector&&) = default;
// assignment
CVector& operator=(CVector const& other)
{
auto temp = other;
swap(temp);
return *this;
}
CVector& operator=(CVector&& other) = default;
// no need for a destructor. unique_ptr takes care of it
void swap(CVector& other) noexcept
{
using std::swap;
swap(data_, other.data_);
swap(size_, other.size_);
}
private:
// defer memory ownership to a class built for the job.
std::unique_ptr<int[]> data_;
std::size_t size_;
};