Использование динамического массива внутри класса - получение ошибки во время компиляции - PullRequest
1 голос
/ 04 июня 2011

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

Привет всем -

Как вы, без сомнения, увидите, основываясь на этом вопросе, я новичок в 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]. Это буквальное значение ноль, и вы для без знака? Я проверил в отладчике, что 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&);
};

Ответы [ 2 ]

0 голосов
/ 05 июня 2011

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

0 голосов
/ 04 июня 2011

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, никакого автоматического изменения размера, например, или буферизации емкости (и нескольких других недостатков), и я вполне уверен, что, возможно, забыл пару вещей, но это начало.

...