Search code examples
c++exceptionstdinitializerlist

How to use exception handling with initializer-list with constructor?


I used to use initialization list through Constructor and everything went well. But now I need some exception handling in my class.

So here is some sample code:

1- Without exception handling

class CVector{
    public:
        CVector(const int);
    protected:
        int* pInt;
        int size;
};

CVector::CVector(const int sz) :
    pInt{ new int[sz]}, size{ sz}{

}

The constructor above doesn't check whether an invalid sized is passed, or new failed...

Now I edited the constructor to handle exceptions:

2- With exception handling:

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
}
  • The problem now: Are they exclusive? - I mean How to mix exception handling with initialization-list through Constructor?

Solution

  • On first view, it's not clear whether you intend CVector to responsibility for owning the dynamic of integers or not. You probably do.

    Almost without fail, you will want each class in your program to manage at most one dynamic resource (such as allocated memory). This is because the job becomes onerous when there is more than one resource.

    In your case, the resource is the int array. So let's give CVector the responsibility, and let's manage that responsibility using a 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_;
    };