Pointer handle - follow-up This is a followup to:


Pointer class/handle


Please review this pointer class.

template&lt;typename T&gt;
class Ptr {
public:
    Ptr(T* t, int s = 1) {
        sz = s;
        p = new T[sz];
        for (int i = 0; i &lt; sz; ++i) {
            p[i] = t[i];
        }
    }

    Ptr(const Ptr&amp; t) {
        sz = t.sz;
        p = new T[sz];
        T* x = t.get();
        for (int i = 0; i &lt; sz; ++i) {
            p[i] = x[i];
        }
    }

    Ptr&amp; operator=(const Ptr&amp; t) {
        Ptr copy{t};
        std::swap(copy.sz, sz);
        std::swap(copy.p, p);
        return *this;
    }

    Ptr(Ptr &amp;&amp;t) :p{t.p}, sz{t.sz} {
        t.p = nullptr;
        t.sz = 0;
    }

    Ptr&amp; operator=(Ptr &amp;&amp;t) {
        std::swap(t.p,p);
        std::swap(t.sz,sz);
        return *this;
    }

    T&amp; operator*() {
        check_range();
        return *p;
    }

    T&amp; operator[](int i) {
        check_range(i);
        return p[i];
    }

    T* get() const {
        return p;
    }

    void operator+=(int i) {
        check_range(index+i);
        index += i;
        p+= i;
    }

    void operator-=(int i) {
        check_range(index-i);
        index -= i;
        p -= i;
    }

    Ptr operator+(int i) {
        Ptr old{*this};
        old+=i;
        return old;
    }

    Ptr operator-(int i) {
        Ptr old{*this};
        old-= i;
        return old;
    }

    Ptr&amp; operator++() {
        operator+=(1);
        return *this;
    }

    Ptr operator++(int) {
        Ptr&lt;T&gt; old{p};
        operator++();
        return old;
    }

    Ptr&amp; operator--() {
        operator-=(1);
        return *this;
    }

    Ptr operator--(int) {
        Ptr&lt;T&gt; old{p};
        operator--();
        return old;
    }

    ~Ptr() {
        delete[] p;
    }

private:
    T* p;
    int sz;
    int index = 0;

    void check_range(int i) {
        if (i &lt; 0 || i &gt; sz-1) {
            throw std::out_of_range("out of range");
        }
    }

    void check_range() {
        if (p == nullptr) {
            throw std::out_of_range("null pointer");
        }
    }

};
c++11 Allows constructor chaining:

Ptr(const Ptr&amp; t) {
    sz = t.sz;
    p = new T[sz];
    T* x = t.get();
    for (int i = 0; i &lt; sz; ++i) {
        p[i] = x[i];
    }
}


Can be written as:

Ptr(const Ptr&amp; t): Ptr(t.p, t.sz) {}


Good to see you using the copy and swap idiom.

Ptr&amp; operator=(const Ptr&amp; t) {
    Ptr copy{t};
    std::swap(copy.sz, sz);
    std::swap(copy.p, p);
    return *this;
}


But his can be simlified by making the compiler to the copy.

Ptr&amp; operator=(Ptr copy) {
        //   ^^^^^    Pass by value is generating a copy.       
    std::swap(copy.sz, sz);
    std::swap(copy.p, p);
    return *this;
}


This looks good.

~Ptr() {
    delete[] p;
}


But you ca still move p

void operator+=(int i) {
    check_range(index+i);
    index += i;
    p+= i;               // P has changed
}

void operator-=(int i) {
    check_range(index-i);
    index -= i;
    p -= i;               // P has changed
}


Thus using it with delete after the point it changed is going to cause UB.