Умный указатель и массив

310
20 декабря 2016, 22:25

Задача поставлена следующим образом: создать класс умный указатель, с которым можно будет реализовать следующее:

int main()
{
    SmartPointer <int> p1 = new int(2);
    p1->Method1();
    p1[2] = int(); // должна быть ошибка на этапе компиляции
    SmartPointer <int[]> p2 = new int[3];
    p2->Method1(); //должна быть ошибка на этапе компиляции
    p2[2] = int();
    return 0;
}

если создаем объект Object = new Object(3); - тогда мы можем обратиться с помощью стрелки ко всем методам которыми обладает объект Object если мы создали массив объект Object = new Object[3] - тогда мы не можем обратиться с помощью стрелки к массиву.

Код ниже:

template <typename T>
class SmartPointer
{
private:
    DefaultDeleter<T> m_deleter;
    Counter *m_count = nullptr;
    T *m_ptr = nullptr;
    typedef std::remove_all_extents_t<T> ptr;
public:
    SmartPointer(T* const ptr) :
        m_count(new Counter),
        m_ptr(ptr)
    {
        m_count->incrementCount();
    }
    SmartPointer(const SmartPointer &source)
        m_count(source.m_count),
        m_ptr(source.m_ptr)
    {
        m_count->incrementCount();
    }
    SmartPointer& operator=(const SmartPointer &right)
    {
        m_count->decrementCount();
        return SmartPointer(right).Swap(*this);
    }
    T& operator*()
    {
        return *m_ptr;
    }
    T* operator->()
    {
        return m_ptr;
    }
    T& operator[](unsigned int index)
    {
        return m_ptr[index];
    }

    SmartPointer& Swap(SmartPointer& other)
    {
        std::swap(m_ptr, other.m_ptr);
        return *this;
    }
    ~SmartPointer()
    {
        {
            m_count->decrementCount();
            if (m_count->getCount() == 0)
            {
                m_deleter.Delete(m_ptr);
                delete m_count;
            }
        }
    }
};
template <typename T>
class DefaultDeleter 
{
public:
    void Delete(T* const ptr)
    {
        delete ptr;
    }
};
template <typename T>
class DefaultDeleter<T[]> 
{
public:
    void Delete(T* const ptr)
    {
        delete[] ptr;
    }
};
class Counter
{
private:
    unsigned int m_uses=0;
    public:
    void incrementCount()
    {
    ++m_uses;
    }
    void decrementCount()
    {
    --m_uses;
    }
    unsigned int getCount()
    {
    return m_uses;
    }
};

Не совсем понятно как сделать так что бы компилятор понимал где (), а где [] где один элемент, а где массив элементов + как исправить ошибку в этой строке кода:

SmartPointer <int[]> p2 = new int[3]; 
Answer 1

Вам нужно просто сделать два разных класса: один для массива, другой - для скаляра. Так же это сделано для std::unique_ptr. Пример:

template <class T>
struct smartPtr {
    T* operator->() { return ptr; }
    T* ptr;
};
template <class T>
struct smartPtr<T[]> {
    T& operator[](int i) { return ptr[i]; }
    T* ptr;
};
struct A { 
    void foo() {}
};
int main()
{
    smartPtr<A> ip;
    ip->foo();   
    ip[0]; // error
    smartPtr<A[]> ia;
    ia->foo(); // error
    ia[0].foo(); 
}
READ ALSO
Пункты меню &ldquo;Окно&rdquo; MDI-приложения

Пункты меню “Окно” MDI-приложения

Как в Qt можно реализовать меню "Окно" MDI-приложения, отражающее открытые внутренние окна и позволяющее переключаться между ними? Пока приходит...

434
Как добавить путь в REST API на QTcpSocket

Как добавить путь в REST API на QTcpSocket

написал простенький класс который работает как однопоточный http сервер, выдающий текущее время и дату, если обратиться по 1270

322
Как правильно умножить число на десять и прибавить другое число? [требует правки]

Как правильно умножить число на десять и прибавить другое число? [требует правки]

Когда я записываю цифру в переменную, цифра храниться до того момента, покуда я другое значение не запишу, а мне нужно сделать, чтоб старое...

420