Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.86/7: Рейтинг темы: голосов - 7, средняя оценка - 4.86
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
1

Ошибки с деаллокацией памяти, выделенной через placement new

05.03.2021, 15:51. Показов 1461. Ответов 11

Author24 — интернет-сервис помощи студентам
Всем привет, следующий код вызывает ошибку в деструкторе класса для объекта b при вызове delete[]. Не понимаю в чем тут проблема и прошу помочь мне ее исправить. Заранее благодарю!

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <cstddef>
 
template <typename T>
class Array
{
private:
    T* m_data;
    size_t m_size;
public:
    explicit Array() : m_data(nullptr), m_size(0) {}
 
    explicit Array(size_t size, const T& value = T()) : m_size(size) {
        char * buffer = new char[m_size * sizeof(T)];
        T* start = nullptr;
        for (size_t i = 0; i < m_size; i++){
            m_data = new (buffer + i * sizeof(T)) T (value);
            if (!i)
                start = m_data;
        }
        m_data = reinterpret_cast<T*>(start);
    }
 
    Array(const Array & arr) {
        m_data = new T[arr.m_size];
        m_size = arr.m_size;
        for (size_t i = 0; i < m_size; i++) {
            *(m_data + i) = *(arr.m_data + i);
        }
    }
 
    ~Array() {
        for (size_t i = 0; i < m_size; i++)
            m_data[i].~T();
        operator delete[] ((char*)m_data);
    }
 
    Array& operator=(const Array& arr){
        if (this != &arr) {
            for (size_t i = 0; i < m_size; i++)
                m_data[i].~T();
            operator delete[] ((char*)m_data);
            m_data = new T[arr.m_size];
            m_size = arr.m_size;
            for (size_t i = 0; i < m_size; i++) {
                *(m_data + i) = *(arr.m_data + i);
            }
        }
        return *this;
    }
    size_t size() const {
        return m_size;
    }
    // T& operator[](size_t)
    T& operator[](size_t i) {
        return *(m_data + i);
    }
    // const T& operator[](size_t) const
    const T& operator[](size_t i) const {
        return *(m_data + i);
    }
};
 
 
int main () {
    typedef Array<float> ArrayF;
    typedef Array<ArrayF> AArrayF;
 
    ArrayF a0(1, 3.14);
    std::cout << "a0 created" << std::endl;
    std::cout << a0[0] << std::endl << std::endl;
 
    AArrayF a(5, a0); // default constructor
    std::cout << "a created" << std::endl;
    std::cout << a[2][0] << std::endl << std::endl;
 
    AArrayF b(a); // copy constructor
    std::cout << "b created" << std::endl << std::endl;
    return 0;
}
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
05.03.2021, 15:51
Ответы с готовыми решениями:

Освобождение памяти, выделенной через new
Я прочитал, что память динамически для строки, можно выделить к примеру узнать длину строки...

Освобождение только части выделенной памяти через new
Здравствуйте, Философски-абстрактный вопрос: Подскажите пожалуйста, а почему память...

Стоит ли при динамическом распределении памяти перехватывать возможные ошибки через try/catch?
Здравствуйте. Обращаюсь к опытным. Скажите, стоит ли при каждом динамическом распределении...

Удаление выделенной памяти
#include &lt;iostream&gt; using namespace std; int main() { int localVariable = 5; int *...

11
2832 / 2337 / 707
Регистрация: 29.06.2020
Сообщений: 8,658
05.03.2021, 16:59 2
У меня вопрос.
Почему выделяете память
m_data = new T[arr.m_size];
а удаляете как char *
operator delete[] ((char*)m_data);
???
и как оно должно работать ?

Добавлено через 6 минут
не проще дать компилятору самому просчитать сколько чего надо удалить ?
C++
1
delete [] m_data;
0
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
05.03.2021, 17:23  [ТС] 3
SmallEvil, так как я выделил char *, решил удалять тоже как char *. Но даже Вашим способом ошибку не исправляет. Ну и по поводу operator delete - "operator delete[] (m_data)" - вызов функции, через которую реализован оператор delete. Эта функция принимает void * и не вызывает деструкторы.

И вот я кстати не уверен, а вызовет ли delete [] m_data; деструкторы для T на всех платформах или это гарантирует компилятор (если я выделял под char)? Просто если это выполняется с помощью какой-то метаинформации и проверяется в самой делаокации, то это может быть проблемой.

UPDATE: только щас понял вопрос, действительно, в конструкторе копирования я выделяю как T и это походу ошибка. >_<

Добавлено через 8 минут
SmallEvil, а так правильнее? Походу тут утечка, по-крайней мере ноет санитайзер, но я ее не вижу :c
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
template <typename T>
class Array
{
private:
    T* m_data;
    size_t m_size;
public:
    explicit Array() : m_data(nullptr), m_size(0) {}
 
    explicit Array(size_t size, const T& value = T()) : m_size(size) {
        char * buffer = new char[m_size * sizeof(T)];
        T* start = nullptr;
        for (size_t i = 0; i < m_size; i++){
            m_data = new (buffer + i * sizeof(T)) T (value);
            if (!i)
                start = m_data;
        }
        m_data = reinterpret_cast<T*>(start);
    }
 
    Array(const Array & arr) {
        m_size = arr.m_size;
        char * buffer = new char[m_size * sizeof(T)];
        T* start = nullptr;
        for (size_t i = 0; i < m_size; i++) {
            m_data = new (buffer + i * sizeof(T)) T (*(arr.m_data + i));
            if (!i)
                start = m_data;
        }
        m_data = reinterpret_cast<T*>(start);
    }
 
    ~Array() {
        for (size_t i = 0; i < m_size; i++)
            m_data[i].~T();
        operator delete[] ((char*)m_data);
    }
 
    Array& operator=(const Array& arr){
        if (this != &arr) {
            for (size_t i = 0; i < m_size; i++)
                m_data[i].~T();
             operator delete[] ((char*)m_data);
            m_size = arr.m_size;
            char * buffer = new char[m_size * sizeof(T)];
            T* start = nullptr;
            for (size_t i = 0; i < m_size; i++) {
                m_data = new (buffer + i * sizeof(T)) T (*(arr.m_data + i));
                if (!i)
                    start = m_data;
            }
            m_data = reinterpret_cast<T*>(start);
        }
        return *this;
    }
    size_t size() const {
        return m_size;
    }
    // T& operator[](size_t)
    T& operator[](size_t i) {
        return *(m_data + i);
    }
    // const T& operator[](size_t) const
    const T& operator[](size_t i) const {
        return *(m_data + i);
    }
};
0
2832 / 2337 / 707
Регистрация: 29.06.2020
Сообщений: 8,658
05.03.2021, 17:58 4
я так и не понял зачем Вам placment new здесь ?
0
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
05.03.2021, 18:01  [ТС] 5
SmallEvil, мой конструктор принимает вторым параметром значение по умолчанию для всех элементов массива. Но если у объекта не будет конструктора по умолчанию, то я не смогу просто выделить new T[m_size], для этого я выделаю массив char'ов и на них уже по элементно вызываю копирующий конструктор объекта типа T для инициализации значением по умолчанию!
0
2832 / 2337 / 707
Регистрация: 29.06.2020
Сообщений: 8,658
05.03.2021, 18:35 6
Лучший ответ Сообщение было отмечено HamsterGamer как решение

Решение

я только мельком знакомился с placment new, тут надо серьзеней,
но Вы не выделили сырую память.

Так тоже утечки ?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include <iostream>
#include <cstddef>
 
template <typename T>
class Array
{
private:
    T* m_data = nullptr;
    size_t m_size = 0;
public:
    explicit Array() : m_data(nullptr), m_size(0) {}
 
    explicit Array(size_t size, const T& value = T()) : m_size(size) {
      if (m_size==0)
          return;
      m_data = (T*) operator new (m_size * sizeof(T));
        for (size_t i = 0; i < m_size; i++)
            new (m_data + i) T (value);
    }
 
    Array(const Array & arr) {
        m_size = arr.m_size;
         if (m_size==0)
          return;
      m_data = (T*) operator new (m_size * sizeof(T));
        for (size_t i = 0; i < m_size; i++)
            new (m_data + i) T (*(arr.m_data + i));
    }
 
    ~Array() {
      if (m_size==0)
          return;
        for (size_t i = 0; i < m_size; i++)
            m_data[i].~T();
        operator delete (m_data);
    }
 
 
    size_t size() const {
        return m_size;
    }
    // T& operator[](size_t)
    T& operator[](size_t i) {
        return *(m_data + i);
    }
    // const T& operator[](size_t) const
    const T& operator[](size_t i) const {
        return *(m_data + i);
    }
};
 
 
int main () {
    typedef Array<float> ArrayF;
    typedef Array<ArrayF> AArrayF;
 
    ArrayF a0(1, 3.14);
    std::cout << "a0 created" << std::endl;
    std::cout << a0[0] << std::endl << std::endl;
 
    AArrayF a(5, a0); // default constructor
    std::cout << "a created" << std::endl;
    std::cout << a[2][0] << std::endl << std::endl;
 
    AArrayF b(a); // copy constructor
    std::cout << "b created" << std::endl << std::endl;
    std::cout << b[2][0] << std::endl << std::endl;
 
    return 0;
}
Добавлено через 5 минут

Добавлено через 1 минуту
operator delete [](m_data);
1
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
05.03.2021, 18:36  [ТС] 7
SmallEvil, да, но похоже дело не в них, а в том, что тестовая система куда я кидаю уже померла от старости. Так как санитайзер от gcc никаких утечек ни в мой и ни в Ваш код не кидает. Буду считать что моя реализация валидна. Спасибо за помощь!

Действительно, можно же было использовать ::operator new, кт по сути работает как malloc, спасибо. Буффер char'ов тут скорее лишний и может замедлить работу из-за выравниваний, которых не учтет ОС при выделении + на платформах, где char != 1 байт я сожру больше чем нужно!
0
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,341
05.03.2021, 18:42 8
HamsterGamer, если что, обёртка такая уже имеется в языке - std::optional

правда, там нужный размер заранее выделяется
1
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
05.03.2021, 18:46  [ТС] 9
Алексей1153, да я знаю о нем, но по заданию было необходимо найти решение с помощью размещающего new
0
фрилансер
5498 / 5094 / 1047
Регистрация: 11.10.2019
Сообщений: 13,341
05.03.2021, 18:59 10
HamsterGamer, ну, тогда также должно быть известно про пачки параметров шаблонов и пробрасывающую ссылку. И решить передачу параметров в конструктор так же, как это делается в optional
0
40 / 29 / 11
Регистрация: 21.06.2019
Сообщений: 201
05.03.2021, 19:08  [ТС] 11
SmallEvil, Всё таки там была утечка, я ее поправил. Мде, смарт поинтеры конечно притупили мне чутье xD

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
template <typename T>
class Array
{
private:
    T* m_data;
    size_t m_size;
public:
    explicit Array() : m_data(nullptr), m_size(0) {}
 
    explicit Array(size_t size, const T& value = T()) : m_size(size) {
        if (m_size) {
            char * buffer = new char[m_size * sizeof(T)];
            T* start = nullptr;
            for (size_t i = 0; i < m_size; i++){
                m_data = new (buffer + i * sizeof(T)) T (value);
                if (!i)
                    start = m_data;
            }
            m_data = reinterpret_cast<T*>(start);
        } else 
            m_data = nullptr;
    }
 
    Array(const Array & arr) {
        m_size = arr.m_size;
        if (m_size) {
            char * buffer = new char[m_size * sizeof(T)];
            T* start = nullptr;
            for (size_t i = 0; i < m_size; i++) {
                m_data = new (buffer + i * sizeof(T)) T (*(arr.m_data + i));
                if (!i)
                    start = m_data;
            }
            m_data = reinterpret_cast<T*>(start);
        } else 
            m_data = nullptr;
    }
 
    ~Array() {
        for (size_t i = 0; i < m_size; i++)
            m_data[i].~T();
        operator delete[] (m_data);
    }
 
    Array& operator=(const Array& arr){
        if (this != &arr) {
            for (size_t i = 0; i < m_size; i++)
                m_data[i].~T();
            operator delete[] (m_data);
 
            m_size = arr.m_size;
            if (m_size) {
                char * buffer = new char[m_size * sizeof(T)];
                T* start = nullptr;
                for (size_t i = 0; i < m_size; i++) {
                    m_data = new (buffer + i * sizeof(T)) T (*(arr.m_data + i));
                    if (!i)
                        start = m_data;
                }
                m_data = reinterpret_cast<T*>(start);
            } else 
                m_data = nullptr;
        }
        return *this;
    }
 
    size_t size() const {
        return m_size;
    }
 
    T& operator[](size_t i) {
        return *(m_data + i);
    }
 
    const T& operator[](size_t i) const {
        return *(m_data + i);
    }
};
Добавлено через 3 минуты
Алексей1153, не понял, как примерно должна выглядеть сигнатура? Просто я не понимаю зачем мне тут нужны variadic template's (если я правильно понял о чем Вы). Цель - это передать одно значение типа T и установить его дефолтным для всего массива. Сделать это на этапе компиляции нельзя, так как значение может быть не consteval
0
6579 / 4564 / 1843
Регистрация: 07.05.2019
Сообщений: 13,726
05.03.2021, 19:16 12
Цитата Сообщение от HamsterGamer Посмотреть сообщение
SmallEvil, Всё таки там была утечка, я ее поправил. Мде, смарт поинтеры конечно притупили мне чутье xD
Цитата Сообщение от HamsterGamer Посмотреть сообщение
            for (size_t i = 0; i < m_size; i++) {
                m_data = new (buffer + i * sizeof(T)) T (*(arr.m_data + i));
Если в конструкторе T возникнет исключение, будет утечка памяти. Т.к. деструктор ~Array() не вызовется. А еcли бы даже вызвался, то отработает неправильно из-за m_size.

Добавлено через 4 минуты
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Array(const Array & arr) 
: Array()
{
    if (!arr.m_size)
        return;
    
    m_data = reinterpret_cast<T*>(new char[m_size * sizeof(T)]);
 
    for (; m_size < arr.m_size; ++m_size) 
        new (m_data+ m_size) T(arr.m_data[m_size]);
}
 
~Array() 
{
    for (size_t i = 0; i < m_size; i++)
        m_data[i].~T();
 
    delete[] reinterpret_cast<char *>(m_data);
}
Что-то типа того
2
05.03.2021, 19:16
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.03.2021, 19:16
Помогаю со студенческими работами здесь

Сдвиг по выделенной памяти С++
Здравствуйте, я начинающий программист (студент) вот... учусь работе со списками После знакомства...

Удаление выделенной памяти
есть такой класс: выделяю память под element *ptemp = new element; и iris *temp = new iris; нужно...

Освобождение выделенной памяти
Здравствуйте! Есть структура, выглядит, например, так: struct some_structure { int* s; } ...

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

Освобождение динамически выделенной памяти
ОС Windows инициировала точку останова в TimeDelay2.exe. Это может быть вызвано повреждением кучи...

Корректно ли освобождение выделенной памяти?
Извиняюсь, если такой вопрос уже звучал. Допустим есть такой кусок кода: struct A { int *x; }...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
12
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru