Использование динамического массива внутри класса Получение ошибки во время компиляции

ВОПРОС ОТВЕЧЕН В КОММЕНТАРИЯХ Из-за моей репутации я не могу ответить на него обычным образом. Позже я добавлю подробности в ответ, уже рассмотренный в комментариях. Спасибо.**

Всем привет -

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

Для класса мне нужно создать оболочку для массива, типизированного целыми числами. (На этом этапе класса нет шаблонов) Мне также нужно разрешить классу иметь ненулевой начальный индекс. Я использую массив элементов в классе для хранения своих данных (в этой точке класса пока нет векторов) и выполняю некоторый перевод из общедоступных методов для доступа к соответствующему внутреннему элементу массива.

Проблема, с которой я сталкиваюсь, заключается в том, что я не знаю размер внутреннего массива во время компиляции, поэтому я объявляю его как глобальный указатель класса и устанавливаю размер в конструкторе. Фрагмент кода находится ниже в проблемной области:

int *list;
safeArray::safeArray(int start, int initialSize)
{
    if(initialSize <= 0)
    {
        throw "Array size must be a positive integer";
    }
    maxSize = initialSize + 1;
    startIndex = start;
    endIndex = start + initialSize;
    list = new int[maxSize];    // Error thrown here
    int *tempArray = new int[maxSize];
    copyArray(tempArray);
    clearArray();   
}

Ошибка, которую я получаю,

Incompatible types in assignment of 'int*' to 'int[0u]'

Я не уверен на 100%, что такое тип int[0u]. Это буквальное значение ноль, а u для беззнакового? Я проверил в отладчике, что maxSize содержит значение, а также заменил его постоянным целочисленным значением и получил ту же ошибку.

Поскольку моя строка int *tempArray = new int[maxSize]; работала, я подумал, что это может быть связано с необходимостью одновременного объявления и размера, поэтому я решил сделать memcpy. (Что на самом деле выходит за рамки задания, поэтому должно быть что-то еще, что я упускаю) Memcpy терпит неудачу, потому что кажется, что я затираю свои другие переменные. Когда я печатаю адрес списка в GDB, он дает мне тот же адрес, что и другая глобальная переменная в моем коде, поэтому этот маршрут также казался выходящим за рамки назначения.

Общая тема, которую я видел на других форумах, заключается в том, что вы не можете назначать массивы, как другие переменные, но я не думал, что это будет включать оператор new. Я ошибаюсь в этом предположении?

Единственные ошибки компиляции, которые я сейчас вижу, это та, что указана выше, и я вижу ее для каждого оператора list = new int[maxSize]; в коде.

Мои вопросы:

  1. Что такое тип int[0u] и где этот тип генерируется? Это должно быть из нового заявления, верно?

  2. Как лучше всего использовать ресурс динамического массива внутри класса? Помимо использования вектора? знак равно

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

/*
 *  safeArray.cpp
 *  safearray
 *
 *  Created by Jeffery Smith on 6/1/11.
 *  
 *
 */

#include "safeArray.h"
#include &lt;iostream&gt;


using namespace std;


    int startIndex = 0;
    int endIndex = 0;
    int maxSize = 1;
    int currentSize = 0;
    int *list;

safeArray::safeArray(int start, int initialSize)
{
    if(initialSize <= 0)
    {
        throw "Array size must be a positive integer";
    }
    maxSize = initialSize + 1;
    startIndex = start;
    endIndex = start + initialSize;
    list = new int[maxSize];    // Error thrown here
    int *tempArray = new int[initialSize + 1];
    copyArray(tempArray);
    clearArray();

}

safeArray::safeArray(const safeArray &sArray)
{
    list = new int[sArray.maxSize];
    copyArray(sArray);
    startIndex = sArray.startIndex;
    endIndex = sArray.endIndex;
    maxSize = sArray.maxSize;
    currentSize = sArray.currentSize;
}

void safeArray::operator=(const safeArray &right)
{
    list = new int[right.maxSize];
    copyArray(right);
    startIndex = right.startIndex;
    endIndex = right.endIndex;
    maxSize = right.maxSize;
    currentSize = right.currentSize;
}

safeArray::~safeArray()
{
    delete [] list;
}



int safeArray::operator[](int index)
{
    if(OutofBounds(index))
    {
        throw "You tried to access an element that is out of bounds";
    }
    return list[index - startIndex];
}

void safeArray::add(int value)
{
    if(this->isFull())
    {
        throw "Could not add element. The Array is full";
    }
    currentSize++;
    list[currentSize + startIndex];
}

void safeArray::removeAt(int value)
{
    if(OutofBounds(value))
    {
        throw "The requested element is not valid in this list";
    }
    compressList(value);
    currentSize--;
}

void safeArray::insertAt(int location, int value)
{
    if(OutofBounds(location) || this->isFull())
    {
        throw "The requested value is either out of bounds or the list is full";
    }
    expandList(location, value);
    currentSize++;
}


void safeArray::clearList()
{
    clearArray();
}

bool safeArray::isFull()
{
    return(maxSize == currentSize);
}

int safeArray::length()
{
    return currentSize;
}

int safeArray::maxLength()
{
    return this->maxSize;
}

bool safeArray::isEmpty()
{
    return(currentSize == 0);
}

bool safeArray::OutofBounds(int value)
{
    return (value > endIndex || value < startIndex);
}

void safeArray::clearArray()
{
    for(int i = 0; i < maxSize; i++)
    {
        list[i] = 0;
    }
    currentSize = 0;
}

void safeArray::compressList(int value)
{
    for(int i = value; i < endIndex; i++)
    {
        list[i] = list[i + 1];
    }
}

void safeArray::expandList(int location, int value)
{
    int tempHolder = list[location];
    list[location] = value;
    for(int i = location; i < endIndex; i++)
    {
        tempHolder = list[location];
        list[location] = value;
        value = tempHolder;
    }
}

void safeArray::copyArray(int *srcAddr )
{

    memcpy(list, srcAddr, sizeof(int) * maxSize);

}

void safeArray::copyArray(const safeArray &sArray)
{

    memcpy(list, &sArray, sizeof(int) * maxSize);

}

Вот определение заголовка:


/*
 *  safeArray.h
 *  safearray
 *
 *  Created by Jeffery Smith on 6/1/11.
 *  Copyright 2011 Accenture. All rights reserved.
 *
 */



class safeArray {

public:
    safeArray(int,int);    //Standard constructor
    ~safeArray();          //Destructor
    int operator[](int);
    void operator=(const safeArray&);   //Assignment overload
    safeArray(const safeArray &sArray); //Copy Constructor

    void add(int);
    int maxLength();
    int length();
    bool isFull();
    bool isEmpty();
    void clearList();
    void removeAt(int);
    void insertAt(int,int);

protected:
    int list[];
    int startIndex;
    int endIndex;
    int maxSize;
    int currentSize;

private:
    void clearArray();
    bool OutofBounds(int);
    void expandList(int,int);
    void compressList(int);
    void copyArray(int*);
    void copyArray(const safeArray&);
};

person Jeffery Smith    schedule 04.06.2011    source источник
comment
Опубликуйте определение class safeArray. Есть ли у него член по имени list? У вас есть list, объявленный как массив, а не указатель. Также обратите внимание, что использование using namespace std;, когда у вас есть такие имена, как list, которые дублируют вещи в пространстве имен std, вероятно, вызовет у вас проблемы.   -  person CB Bailey    schedule 04.06.2011
comment
Вы должны выбрасывать экземпляры std::exception (или подкласса) вместо const char*. Также не используйте здесь <pre> или <code>, сделайте отступ кода с 4 пробелами.   -  person Cat Plus Plus    schedule 04.06.2011
comment
Если когда-либо у класса было вводящее в заблуждение имя, то это оно :-)   -  person    schedule 04.06.2011
comment
да, пространство имен std содержит именованный список классов. Удалите эту строку и повторите попытку или переименуйте переменную. Кроме того, вы объявляете список переменных как локальную переменную, а не как член класса, что вызовет ошибки, если вы создадите два или более экземпляра вашего массива...   -  person Raiv    schedule 04.06.2011
comment
1. Похоже, компилятор считает, что у вас есть list где-то, что может быть объявлено int list[] или int list[0]. Ты? 2. Использование std::vector действительно является хорошей идеей. Разве вы не начинаете видеть это сейчас? :-)   -  person Bo Persson    schedule 04.06.2011
comment
@Бо лол! Да я давно это видел. Я просто хочу посмотреть, что мне не хватает, так что.   -  person Jeffery Smith    schedule 04.06.2011
comment
@ Бо, и ты был прав. У меня было старое объявление int list[] в моем заголовочном файле, которое я никогда не обновлял до указателя. Так что это решило мою проблему. Я знал, что это должно быть что-то простое. Курс является независимым исследованием, поэтому я ни с кем не работаю. Иногда вам просто нужна вторая пара глаз. Большое спасибо! Я запишу это в глупые вещи, чтобы проверить кулак   -  person Jeffery Smith    schedule 04.06.2011
comment
@Cat Plus Plus Спасибо за отзыв. Исключение, которое я сделал, было своего рода заполнителем, пока я не провел больше исследований по исключениям. Это тоже еще не часть задания, но я хотел что-то там, пока я не копнул немного больше. Также извините за вещь с ‹pre›‹code›. Я буду помнить это в будущем. Спасибо.   -  person Jeffery Smith    schedule 04.06.2011
comment
@Charles - Да, оказалось, что у меня была старая декларация, вызывающая проблему. Спасибо. Также я не думал об общем характере списка как переменной. Это не вызвало никаких проблем, но я изменил его в своем коде на всякий случай. Спасибо еще раз!   -  person Jeffery Smith    schedule 04.06.2011


Ответы (2)


int[0u]? Я считаю, что в C вы можете иметь массивы нулевой длины в конце структур, чтобы разрешить эффективное использование структур переменного размера, но это не делается в C++. Я не вижу в вашем коде ничего, что было бы незаконным кодом. Ужасно, да, незаконно, нет. Вам нужно опубликовать содержимое safearray.h, если оно включает стандартные заголовки, то использование вами using namespace std; может легко стать причиной проблемы.

Кроме того, глобальные переменные — это плохо. Просто поместите указатель внутрь класса — вам никогда не придется использовать глобальные переменные, если только вы не делаете что-то очень неправильное. Тем более, что это, скажем, оставляет вас открытым для переменного затенения, конфликтов имен и других серьезных проблем. О, и вы должны генерировать класс исключения, предпочтительно производный от std::exception или std::runtime_error. Никто не будет пытаться поймать const char*. Вы не должны использовать пространство имен std - вы напрашиваетесь на проблемы. И вы не вызываете конструктор копирования или оператор присваивания, а используете memcpy для копирования ваших элементов? У вас также произошла утечка памяти в нескольких местах, начиная с оператора присваивания.

template<typename T> class safe_array {
    char* list;
    std::size_t arrsize;
    void valid_or_throw(std::size_t index) {
        if (index <= arrsize) {
            throw std::runtime_error("Attempted to access outside the bounds of the array.");
    }
public:
    safe_array(std::size_t newsize) 
    : list(NULL) {
        size = arrsize;
        list = new char[arrsize];
        for(std::size_t i = 0; i < arrsize; i++) {
            new (&list[i * sizeof(T)]) T();
        }
    }
    safe_array(const safe_array& ref) 
    : list(NULL) {
        *this = ref;
    }
    safe_array& operator=(const safe_array& ref) {
        clear();
        arrsize = ref.size;
        list = new char[arrsize];
        for(std::size_t i = 0; i < arrsize; i++) {
            new (&list[i * sizeof(T)]) T(ref[i]);
        }        
    }
    T& operator[](std::size_t index) {
        valid_or_throw(index);
        return static_cast<T&>(list[index * sizeof(T)]);
    }
    const T& operator[](std::size_t index) {
        valid_or_throw(index);
        return static_cast<const T&>(list[index * sizeof(T)]);
    }
    void clear() {
        if (list == NULL)
            return;
        for(std::size_t i = 0; i < size; i++) {
            (*this)[i].~T();
        }
        delete[] list;
        list = NULL;
        arrsize = 0;
    }
    std::size_t size() {
        return arrsize;
    }
    bool empty() {
        return (list == NULL);
    }
    ~safe_array() {
        clear();
    }
};

Относительно быстрый пример класса, который я подобрал, должен указать вам более общее направление. Он не предлагает всех функций vector, например, автоматического изменения размера или буферизации емкости (и нескольких других недостатков), и я совершенно уверен, что, вероятно, забыл пару вещей, но это только начало.

person Puppy    schedule 04.06.2011
comment
Спасибо DeadMG. Вы видите глобальную переменную в коде? Я использую глобальную переменную класса. Это не глобально для программы, а только для класса. Это неправильная терминология? Я неправильно объявил это в своем коде? - person Jeffery Smith; 04.06.2011
comment
Еще вопрос к вам, DeadMG. Я вижу в вашем заявлении, что у меня произошла утечка памяти при перегрузке оператора присваивания. Должен ли я опубликовать список? Это ресурс в классе, который освобождается в методе деструктора. Разве этого недостаточно? - person Jeffery Smith; 05.06.2011

@Bo помог мне в комментариях. Оказывается, у меня было старое объявление int list[] в заголовочном файле, которое я никогда не менял. Так что ошибка компилятора, которую он выдавал, была связана с объявлением там. После этого все было подливкой.

person Jeffery Smith    schedule 05.06.2011