Распределение памяти в C ++ (Исключение: нарушение прав чтения.) - PullRequest
0 голосов
/ 30 октября 2019

Я пытаюсь узнать немного больше о C ++! Поработав некоторое время с распределением памяти, я добрался до места, где я изо всех сил пытался это понять.

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

Буду признателен, если кто-нибудь сможет мне объяснить, что происходит и как я могу решить эту проблему.

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

delete[] pointer; //PROBLEMATIC LINE

PS .: Я не ищу альтернативных решений (например, использование умных указателей или чего-то еще). Извините за мой английский!

Код:

class class1
{
private:
    unsigned int    s;
    double* pointer;
public:
/* Constructors */
    class1() { s = 0; pointer = nullptr; }
    class1(unsigned int us, double* uarray)
    {
        pointer = new double[us];
        for (unsigned int i = 0; i < us; i++)
            pointer[i] = uarray[i];
    }
    class1(const class1& other)
    {
        pointer = new double[s];
        for (unsigned int i = 0; i < s; i++)
            pointer[i] = other.pointer[i];
    }
    ~class1() { if (!s && pointer != nullptr) delete[] pointer; }

public:
/* Operators Overloading */
    class1& operator=(const class1& other)
    {
        s = other.s;
        pointer = new double[s];
        for (unsigned int i = 0; i < s; i++)
            pointer[i] = other.pointer[i];
        return *this;
    }
};

class class2
{
private:
    unsigned int    m;
    unsigned int    n;
    class1* pointer;

public:
/* Constructors */
    class2(unsigned int un, double* uarray, bool flag = false) : n(un)
    {
        m = 1;
        pointer = new class1(un, uarray);
        if (flag) { this->function(); }
    }
    ~class2() { if (!m && !n) delete[] pointer; }

public:
/* Public Methods */
    void function()
    {
        class1* newpointer = new class1[n];
        //**... some code (when commented show the same error)**
        delete[] pointer; //**PROBLEMATIC LINE**
        pointer = newpointer;
    }

public:
/*Template Constructor*/
    template<unsigned int m, unsigned int n>
    class2(unsigned int um, unsigned int un, double(&uarray)[m][n], bool flag = false) : m(um), n(un)
    {
        pointer = new class1[um];
        for (unsigned int i = 0; i < um; i++)
        {
            class1 object1(un, uarray[i]);
            pointer[i] = object1;
        }
        if (flag) { this->function(); }
    }
};

int main()
{
    double test3[] = { 1, 2, 3 };
    double test4[][3] = { {3, 2, 1}, {6, 5, 4}, {9, 8, 7} };
    double test5[][3] = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };

    class2 m4(3, test3, true);      //**NOT OK - VIOLATION OF MEMORY**
    class2 m5(3, 3, test4, true);   //**OK**
}

1 Ответ

1 голос
/ 30 октября 2019

Ваш конструктор копирования для class1 не устанавливает член s, но использует здесь его неопределенное значение:

pointer = new double[s];

, вызывая неопределенное поведение. Установите s из other.s перед его использованием.


У вашего второго конструктора такая же проблема.


Ваш оператор присваивания class1 вызывает утечку памяти, посколькуэто не delete[] предыдущий массив.


В class2 вы используете new в форме не-массива, например, здесь:

pointer = new class1(un, uarray);

, но вдеструктор, которого вы вызываете delete[], чтобы удалить pointer. Это также вызывает неопределенное поведение. Указатели, возвращенные из не-массивной версии new, должны быть удалены с помощью delete, например, delete pointer.

Но так как вы также используете версию массива new для pointer,Вы также не можете использовать delete pointer. Использование delete вместо delete[] для указателя, возвращаемого из массива-new, также имеет неопределенное поведение.

Будьте последовательны и всегда используйте массив-новый, например:

pointer = new class1[1]{{un, uarray}};

class2 вызывает неопределенное поведение, когда объект его типа копируется или перемещается, потому что вы не реализовали конструктор копирования и оператор присваивания, хотя вы определили деструктор. Это нарушение правила трех .


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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...