Ошибка перегрузки индекса массива - PullRequest
0 голосов
/ 12 февраля 2020

Почему этот код приводит к тому, что второй элемент массива печатается как 0, независимо от значения, которое было указано в определении объекта целочисленного массива? Вывод кода ниже 7 7 3 4 5 6 вместо 7 2 3 4 5 6, что может быть причиной такого поведения?

// Overloading operators for Array class
#include<iostream>
#include<cstdlib>

using namespace std;

// A class to represent an integer array
class Array
{
private:
    int *ptr;
    int size;
public:
    Array(int *, int);

    // Overloading [] operator to access elements in array style
    int &operator[] (int);

    // Utility function to print contents
    void print() const;
};

// Implementation of [] operator.  This function must return a
// reference as array element can be put on left side
int &Array::operator[](int index)
{
    if (index >= size)
    {
        cout << "Array index out of bound, exiting";
        exit(0);
    }
    return ptr[index];
}

// constructor for array class
Array::Array(int *p = NULL, int s = 0)
{
    size = s;
    ptr = NULL;
    if (s != 0)
    {
        ptr = new int[s];
        for (int i = 0; i < s; i++)
            ptr[i] = p[i];
        delete ptr;
    }
}

void Array::print() const
{
    for(int i = 0; i < size; i++)
        cout<<ptr[i]<<" ";
    cout<<endl;
}

// Driver program to test above methods
int main()
{
    int a[] = {1, 2, 3, 4, 5, 6};
    Array arr1(a, 6);
    arr1[0] = 7;
    arr1.print();
    arr1[8] = 6;
    return 0;
}

Ответы [ 3 ]

3 голосов
/ 12 февраля 2020

В конструкторе Array сразу после выделения и заполнения динамически выделенного буфера на ptr буфер освобождается с

delete ptr;

Все обращения к буферу на ptr после этой точки вызвать неопределенное поведение . Примечание: Это должно было быть delete[] ptr;, чтобы гарантировать, что массив был освобожден правильно.

Решение: не делайте этого!

Добавьте деструктор к свободному ptr, когда Array выходит из области видимости и завершается с буфером.

// destructor for array class
Array::~Array()
{
    delete[] ptr;
}

Компилятор автоматически сгенерирует для вас деструктор, но этот деструктор generi c не квалифицирован, чтобы знать, безопасно ли или нет delete[] то, что находится в элементе-указателе. Это может быть не массив, выделение может принадлежать другому объекту (см. Что такое владение ресурсами или указателями? ) или, возможно, динамически не распределяться с new.

. Примечание: специальные функции-члены по умолчанию, которые обрабатывают копирование этого объекта, будут бездумно копировать указатель, а не выделение, и оставят вас с двумя объектами, указывающими на одно и то же выделение. Рано или поздно это станет фатальным, потому что одна копия go выйдет из области видимости раньше другой, и если больше ничего не попытается получить доступ к освобожденному выделению и прервать программу, вторая delete[] сломает программу. Эта проблема и ее решение подробно описаны в Что такое правило трех?

Общее правило - не создавать такой класс, а вместо этого использовать std::vector. std::vector делает все это и многое другое.

0 голосов
/ 18 февраля 2020

Модифицированная функция печати, чтобы исключить пробел после последнего элемента массива. Изменено объявление метода конструктора для включения инициализированных аргументов. Добавлена ​​дополнительная константная версия перегрузки оператора index [], но я не думаю, что она реализована должным образом или действительно будет использоваться.

#include<iostream>
#include<cstdlib>


// A class to represent an integer array
class Array{
private:
    int *ptr;
    std::size_t size;
public:
    Array(int *p = nullptr, std::size_t s = 0);
    Array(const Array&);
    ~Array();
    Array& operator= (Array);

    // Overloading [] operator to access elements in array style
    int &operator[] (std::size_t);

    int const& operator[](std::size_t) const;

    // Utility function to print contents
    void print() const;

    friend void swap(Array& first, Array& second);};


// Implementation of [] operator.  This function must return a
// reference as array element can be put on left side
int &Array::operator[](std::size_t index){
    puts("overload");   
    if (index >= size || index < 0){
       throw std::out_of_range("Index out of Range error");
    }
    return ptr[index];
}

int const& Array::operator[](std::size_t index) const{
    puts("const overload");
    if (index >= size || index < 0){
        throw std::out_of_range("Index out of Range error");
    }
    return ptr[index];
}


// constructor for array class
Array::Array(int *p, std::size_t s){
    size = s;
    ptr = nullptr;
    if (s != 0){
        ptr = new int[s];
        for (int i = 0; i < s; i++){
            ptr[i] = p[i];}
    }
}

// destructor for array class
Array::~Array(){
    delete[] ptr;
    ptr = nullptr;}

// copy constructor for array class
Array::Array(const Array& A) { 
    size = A.size;
    ptr  = new int[size];
    for (int i = 0; i < size; i++){
        ptr[i] = A.ptr[i];}
}
//swap friend function of assignment operator
void swap(Array& first, Array& second){
    using std::swap;
    swap(first.size, second.size);
    swap(first.ptr, second.ptr);}

//Assignment operator for array class
Array& Array::operator=(Array other){
    swap(*this, other); 
    return *this;}

//print function for array elements
void Array::print() const{
    std::cout << "{";
    for(int i = 0; i < size; i++){
        std::cout << ptr[i];
        if (i == size-1){
            continue;}
        std::cout<<" ";       
       }
    std::cout<<"}"<< std::endl;}

// Driver program to test above methods
int main()
{
    int a[] = {1, 2, 3, 4, 5, 6};
    Array arr1(a, 6);
    std::cout << arr1[3] << '\n';
    arr1[4] = 7;
    arr1.print();
    Array arr2 = arr1;
    arr2.print();
    arr1[-1] = 4;
    return 0;
} 

0 голосов
/ 12 февраля 2020

Я изменил код как таковой, добавив в него явный конструктор по умолчанию и конструктор копирования, а также исключение std :: out_of_range, но не уверен, правильно ли он реализован. Это было сделано в качестве упражнения для обработки массивов без использования векторного контейнера из STL. Добавлена ​​функция-член подкачки и оператор присваивания, но получено несколько сообщений об ошибках.

В классе «Массив» нет члена «своп», член «Массив :: размер» (объявлен в строке 12) недоступен » operator = 'должен быть функцией-членом' this 'может использоваться только внутри нестационарной c функции-члена

// Overloading operators for Array class
#include<iostream>
#include<cstdlib>
//#include<vector>

using namespace std;

// A class to represent an integer array
class Array{
private:
    int *ptr;
    int size;
public:
    Array(int *, int);
    Array(const Array&);
    ~Array();
    Array& operator= (Array);

    // Overloading [] operator to access elements in array style
    int &operator[] (int);

    // Utility function to print contents
    void print() const;

    friend void swap(Array& first, Array& second);};


// Implementation of [] operator.  This function must return a
// reference as array element can be put on left side
int &Array::operator[](int index){
    // try {
    //     return ptr[index];}
    // catch(const out_of_range& oor){
    //         cerr << "Out of Range error: " << oor.what() << '\n';}    
    if (index >= size || index < 0){
       throw out_of_range("Index out of Range error");
    }
    return ptr[index];
}

// constructor for array class
Array::Array(int *p = NULL, int s = 0){
    size = s;
    ptr = NULL;
    if (s != 0){
        ptr = new int[s];
        for (int i = 0; i < s; i++)
            ptr[i] = p[i];}
}

// destructor for array class
Array::~Array(){
    delete[] ptr;
    ptr = NULL;}

// copy constructor for array class
Array::Array(const Array& A) { 
    size = A.size;
    ptr  = new int[size];
    for (int i = 0; i < size; i++)
        ptr[i] = A.ptr[i];}

void Array::swap(Array& first, Array& second){
    using std::swap;
    swap(first.size, second.size);
    swap(first.ptr, second.ptr);}

//Assignment operator for array class
Array::Array& operator=(Array other){
    swap(*this, other); 
    return *this;}

//print function for array elements
void Array::print() const{
    cout << "{";
    for(int i = 0; i < size; i++)
        cout<<ptr[i]<<" ";
    cout<<"}"<<endl;}

// Driver program to test above methods
int main()
{
    int a[] = {1, 2, 3, 4, 5, 6};
    Array arr1(a, 6);
    arr1[0] = 7;
    arr1.print();
    Array arr2 = arr1;
    arr2.print();
    arr1[-1] = 4;
    return 0;
} 
...