【问题标题】:How to use exception handling with initializer-list with constructor?如何使用带有构造函数的初始化列表的异常处理?
【发布时间】:2018-01-03 18:54:24
【问题描述】:

我曾经通过构造函数使用initialization list,一切顺利。但是现在我需要一些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
}
  • 现在的问题:它们是专有的吗? - 我的意思是如何通过构造函数将异常处理与初始化列表混合在一起?

【问题讨论】:

  • new 不能返回 nullptr,除非您使用指定 nothrow。它在分配失败时抛出std::bad_alloc。
  • 我不认为这个问题真的与指定的欺骗重复。当不使用智能指针时,它实际上是关于安全资源管理的。 (提示:使用智能指针)。
  • @RichardHodges 谢谢你的提示。请添加答案。
  • @RichardHodges:真不知道为什么这么快就关门了?
  • 通常,您会使用std::vector 并避免所有这些问题。但是,由于您似乎正在尝试实现自己的向量(也许作为学习练习?),那么您可以改用std::unique_ptr&lt;int[]&gt;。在任何情况下,您都应该依赖RAII,而不是尝试捕获异常并手动清理。如果一个类是特定且独特的工作,则只能手动执行此操作。

标签: c++ exception-handling stdinitializerlist


【解决方案1】:

首先,尚不清楚您是否打算让 CVector 负责拥有整数的动态性。你可能会。

几乎没有失败,您会希望程序中的每个类最多管理一个动态资源(例如分配的内存)。这是因为当资源不止一种时,这项工作会变得很繁重。

在您的情况下,资源是 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_;
};

【讨论】:

    【解决方案2】:

    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}
    {}
    

    【讨论】:

      猜你喜欢
      • 2010-10-16
      • 1970-01-01
      • 2022-01-19
      • 2013-07-07
      • 1970-01-01
      • 2010-09-14
      • 2022-12-14
      • 1970-01-01
      相关资源
      最近更新 更多