Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.83/29: Рейтинг темы: голосов - 29, средняя оценка - 4.83
1 / 1 / 0
Регистрация: 22.07.2014
Сообщений: 8

Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error"

22.07.2014, 22:14. Показов 5779. Ответов 9
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте. Возникла проблема с оператором "delete". Пользуюсь VisualStudio 2010. Программа компилируется нормально. Все отрабатывает. Когда дело доходит до освобождения памяти, выделенной операцией "new", вылетает ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)". Если закомментировать вызов "delete" - программа доходит до логического завершения. Очевидно, какая-то проблема с освобождением памяти. Если я выделяю память только на базовые объекты, "delete" нормально отрабатывает. Но при выделении памяти на любой унаследованный объект - вылетает вышеупомянутая ошибка. Похожая программа из книги по "С++", судя по словам автора книги, работает исправно. Вот код моей программы:
1) Заголовочный файл:
C++ (Qt)
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
class Person {
private:
    string name;
    string sname;
public:
    Person(char * n="Name",char * s="Surname") : name(n), sname(s) {}
    ~Person() {}
    virtual void Set();
    virtual void Show() const {
        cout << name << " " << sname << endl;
    }
};
 
class Gunslinger: virtual public Person {
private:
    int count;
protected:
    double Draw() const { return 3.14; }
public:
    Gunslinger(const int & a=0,char * n="Name",char * s="Surname") : Person(n,s), count(a) {}
    void Set();
    int GetCount() const {
        return count;
    }
    void Show() const {
        Person::Show();
        cout << "Количество насечек: " << count << endl;
        cout << "Время приведения в боеготовность: " << Draw() << " секунды." << endl;
    }
};
 
struct Card {
    short name;
    char * suit;
};
class Deck {
private:
    Card Cards[52];
    static char * suits[4];
public:
    Deck();
    Card randomcard() const { return Cards[rand()%51]; }
    friend ostream & operator<<(ostream & os, const Card & C);
};
 
class PokerPlayer : virtual public Person {
private:
    Deck D;
protected:
    Card Draw() const { return D.randomcard(); }
public:
    PokerPlayer(char * n="Name",char * s="Surname") : D(), Person(n,s) {}
    void Set();
    void Show() const { 
        Person::Show();
        cout << Draw();
    }
};
class BadDude: public Gunslinger, public PokerPlayer {
private:
    double Gdraw() const { return Gunslinger::Draw(); }
    Card Cdraw() const { return PokerPlayer::Draw(); }
public:
    BadDude(const int & a=0,char * n="Name",char * s="Surname") : Person(n,s), Gunslinger(a,n,s), PokerPlayer(n,s) {}
    void Set();
    void Show() const {
        Person::Show();
        cout << "Количество насечек: " << Gunslinger::GetCount() << endl;
        cout << "Время приведения в боеготовность: " << Gdraw() << " секунды." << endl;
        cout << "Карта: " << Cdraw() << endl;
    }
};
2) Файл реализации:
C++ (Qt)
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
char * Deck::suits[4]={"spades","clubs","diamonds","hearts"};
 
Deck::Deck() {
    srand(time(NULL));
    int t=2, s=0;
    for(int i=0;i<52;i++,t++) {
        if(t==15) {
            t=2;
            s++;
        }
        Cards[i].name=t;
        Cards[i].suit=suits[s];
        }
};
 
ostream & operator<<(ostream & os, const Card & C) {
    cout << C.name << " of " << C.suit << endl;
    return os;
}
void Person::Set() {
    cout << "Введите имя: ";
    getline(cin,name);
    cout << "Введите фамилию: ";
    getline(cin,sname);
}
void Gunslinger::Set() {
    Person::Set();
    cout << "Введите количество насечек: ";
    cin >> count;
}
void PokerPlayer::Set() {
    Person::Set();
}
void BadDude::Set() {
    Gunslinger::Set();
}
3) Файл исходного кода:
C++ (Qt)
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
void main() {
setlocale(LC_ALL,"Russian");
 
Person * Guys[5]; 
int ct; 
for (ct=0;ct<5;ct++) 
{ 
char choice; 
cout << "Enter the guy category:\n"
<< "p: person g: gunslinger " 
<< "o: pokerplayer b:baddude q: quit\n";
cin >> choice; 
while (strchr("pgobq", choice) == NULL) 
{ 
cout << "Please enter a p, g, o, b or q: "; 
cin >> choice; 
} 
if (choice == 'q') 
break; 
switch(choice) 
{ 
case 'p': Guys[ct] = new Person; 
break; 
case 'g': Guys[ct] = new Gunslinger; 
break; 
case 'o': Guys[ct] = new PokerPlayer;
break;
case 'b': Guys[ct] = new BadDude;
break;
} 
cin.get(); 
Guys[ct]->Set(); 
} 
cout << "\nHere is your staff:\n"; // вывод списка работников 
int i; 
for(i=0;i<ct;i++) 
{ 
cout << endl;
cout << "Объект № " << i+1 << ":\n\n";
Guys[i]->Show(); 
}
for(i=0;i<ct;i++)
delete Guys[i];
cout << "\nDone!\n\n";
}
Все необходимые заголовочные файлы подключены. Помогите пожалуйста решить проблему. Конечно, можно было бы пропустить эту ошибку и изучать язык дальше. Но так не интересно.
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
22.07.2014, 22:14
Ответы с готовыми решениями:

При вызове delete[] _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Функция strtok влияет на массив second, после чего его невозможно удалить, не могу понять чего. first удаляет без проблем. FILE*...

Ошибка pHead->nBlockUse
После выполнения программы выскакивает ошибка. Почитал на форумах, что проблема или в деструкторе или в КК. Но я сам не смог разобраться...

Ошибка _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Здравствуйте. Я работаю с таким кодом. При выполнении строк 92-107 программа выдаёт окно с ошибкой. По всей видимости, что-то не так с...

9
20 / 20 / 3
Регистрация: 14.06.2012
Сообщений: 95
22.07.2014, 22:32
Вообще-то всё нормально, это распространённая ошибка MSVS. Где конкретно показывает ошибку, в стандартных файлах? решается переустановкой студии/перезапуском студии/рестарт винды/переход на новую версию студии
0
1 / 1 / 0
Регистрация: 22.07.2014
Сообщений: 8
22.07.2014, 23:00  [ТС]
Я не совсем понял ваш вопрос. Вот скриншот ошибки:



Возможно он подтолкнет вас на какую-нибудь мысль.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16480 / 7443 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
22.07.2014, 23:24
Цитата Сообщение от IIARTEMII Посмотреть сообщение
Вообще-то всё нормально, это распространённая ошибка MSVS.
Стыдно должно быть писать такую ересь.

Цитата Сообщение от zahvad Посмотреть сообщение
Очевидно, какая-то проблема с освобождением памяти. Если я выделяю память только на базовые объекты, "delete" нормально отрабатывает. Но при выделении памяти на любой унаследованный объект - вылетает вышеупомянутая ошибка.
Про виртуальный деструктор никогда не слышали ?

Цитата Сообщение от zahvad Посмотреть сообщение
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
А теперь нажмите "Retry" и окажетесь в отладчике, с call stack, переменными и т.д.

Цитата Сообщение от zahvad Посмотреть сообщение
Похожая программа из книги по "С++", судя по словам автора книги, работает исправно.
У этого автора весьма своеобразное представление о том, что такое C++.
0
20 / 20 / 3
Регистрация: 14.06.2012
Сообщений: 95
22.07.2014, 23:26
Цитата Сообщение от Убежденный Посмотреть сообщение
Стыдно должно быть писать такую ересь
Ага, и что порой код
C++
1
2
3
int *var = new int(2);
int varvar = *var + 2;
delete var;
вызывает такую же ошибку =// и это только в MSVS
0
1 / 1 / 0
Регистрация: 22.07.2014
Сообщений: 8
22.07.2014, 23:38  [ТС]
Цитата Сообщение от Убежденный Посмотреть сообщение
Про виртуальный деструктор никогда не слышали ?
Спасибо за идею. Сделал деструктор виртуальным и все заработало. Я совсем забыл про него.

Добавлено через 5 минут
IIARTEMII, вам тоже спасибо за помощь.
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16480 / 7443 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
22.07.2014, 23:40
IIARTEMII, какой плохой компилятор этот Microsoft Visual C++ !
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct parent
{
};
 
struct child : public virtual parent
{
};
 
int main()
{
    parent * p = new child();
    delete p;
    return 0;
}

А между тем, полиморфное удаление объекта без виртуального деструктора - UB.
1
20 / 20 / 3
Регистрация: 14.06.2012
Сообщений: 95
22.07.2014, 23:50
Это всё понятно
Теперь у меня вопрос, чтобы не создавать новую тему:
Что это за механизм такой, который реагирует на отсутствие виртуального деструктора, если по сути это приводит к утечке памяти, а не к программной ошибке (да, UB может привести к ошибке, а может и нет, но...)? Почему этот механизм себя проявляет только в MSVS? В других продуктах такого никогда не видел

Ведь если у нас есть базовый класс, есть унаследованный от него дочерний:
C++
1
2
3
Base *ptr = new Der;
// ...
delete ptr;
при отсутствии виртуального деструктора будет вызван деструктор Base, а он, собственно, почистит область памяти, выделенную под объект класса Base (+ выполнение того кода, что у него внутри)

Если схематично представить память, то:
|- - - - Base - - - -| - - Der - - |
при подходе выше, у нас будет:
| - - - - - - - - - - | - - Der - - |
Почему тут ошибка? Или тут немножко всё не так?
0
Ушел с форума
Эксперт С++
 Аватар для Убежденный
16480 / 7443 / 1187
Регистрация: 02.05.2013
Сообщений: 11,617
Записей в блоге: 1
23.07.2014, 01:53
Цитата Сообщение от IIARTEMII Посмотреть сообщение
Что это за механизм такой, который реагирует на отсутствие виртуального деструктора, если по сути это приводит к утечке памяти, а не к программной ошибке (да, UB может привести к ошибке, а может и нет, но...)? Почему этот механизм себя проявляет только в MSVS?
Тут очень многое зависит от деталей реализации - от того, как сделаны
виртуальные таблицы в данном конкретном компиляторе и как устроен его
аллокатор памяти.

Приключения начинаются вот в этой строке:
C++
1
Base *ptr = new Der;
Если Base и Der - обычные классы, не отягощенные virtual-методами,
включая деструктор, то при касте указателя Der к Base его скалярное
значение сохранится. То есть, к примеру, если "new Der" вернет адрес
0xABCDE8, то и в ptr будет записано 0xABCDE8. В этом случае, когда
будет вызван "delete ptr", аллокатор получит все тот же адрес и
сможет корректно освободить занимаемую объектом Der память.
Хотя деструктор Der вызван не будет.

Предположим, Der унаследован не только от Base, но еще и от Megabase,
причем Megabase в списке наследования расположен раньше Base:
C++
1
class Der : public Megabase, public Base { ... };
В этом случае приведение указателя от Der к Base приведет к
изменению его скалярного значения.

Пример:
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
#include <iostream>
 
struct Megabase
{
    virtual void somefunc() {}
};
 
struct Base
{
    virtual void anotherfunc() {}
};
 
struct Der : public Megabase, public Base {};
 
int main()
{
    using namespace std;
 
    Der  * pDer  = new Der();
    Base * pBase = pDer;
 
    cout << pDer  << endl;
    cout << pBase << endl;
 
    // delete pBase; // ???
 
    return 0;
}
> 0x9850438
> 0x985043c
Вот тут и начинаются глюки. "delete pBase" приведет к попытке
освобождения памяти по адресу 0x985043c, хотя при создании объекта
Der был возвращен адрес 0x9850438. Это равноценно тому, что в
delete передали адрес, который никогда не выделялся.
Кстати, возникновение ошибки в данном примере характерно не только
для MS Visual C++, можете проверить на любом компиляторе, который
есть под рукой.

Нечто похожее происходит и при виртуальном наследовании, так как
там "раскладка" классов в памяти заметно отличается от обычной,
хотя все это, повторюсь, очень compiler-specific:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
 
struct parent
{
    int a;
};
 
struct child : public virtual parent
{
    int b;
};
 
int main()
{
    using namespace std;
 
    child Child;
    cout << &Child.a << endl;
    cout << &Child.b << endl;
 
    return 0;
}
> 0x42f80c
> 0x42f808
Неожиданно: a размещается в памяти после b.
При обычном (невиртуальном) наследовании все было бы наоборот.

И последний пример, снова с изменением скалярного значения указателя
при касте к базовому классу:
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
#include <iostream>
 
struct parent
{
    int a;
};
 
struct child : public virtual parent
{
    int b;
};
 
int main()
{
    using namespace std;
 
    child  * pChild  = new child();
    parent * pParent = pChild;
 
    cout << pChild  << endl;
    cout << pParent << endl;
 
    // delete pParent; // ???
 
    return 0;
}
> 0x5712D8
> 0x5712E0
При полиморфном удалении объекта, когда базовый класс имеет виртуальный
деструктор, аллокатор всегда получает "правильный" адрес памяти для очистки,
так что проблем, описанных выше, не возникает.
2
327 / 230 / 55
Регистрация: 30.05.2014
Сообщений: 682
23.07.2014, 04:32
Цитата Сообщение от IIARTEMII Посмотреть сообщение
Что это за механизм такой, который реагирует на отсутствие виртуального деструктора, если по сути это приводит к утечке памяти
Поднимаем глаза и читаем заголовок окна сообщения.
Механизм этот называется MS CRT Debug Library.
При правильном применении очень полезный мехнизм, в том числе и для обнаружения утечек памяти.

http://msdn.microsoft.com/en-u... tc9t1.aspx
http://msdn.microsoft.com/en-u... 80%29.aspx
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
23.07.2014, 04:32
Помогаю со студенческими работами здесь

При вызове деструктора выдается ошибка _BLOCK_TYPE_IS_VALID (pHead->nBlockUse)
Вопрос на форуме поднимался раз 100, но все равно не могу понять в чем проблема. Знаю, что искать нужно в setSpace() и getFlat(). Но что...

При вызове деструктора вылазит ошибка _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
Понимаю,что подобный вопрос на форуме поднимался не раз,но разобраться не могу всё равно. Вот описание класса: class Stroka { ...

Ошибка при запуске программы. _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
В общем C++ только начал осваивать, так что, если будет не трудно, разжевывайте объяснения как можно понятней пожалуйста :) Ошибка...

При освобождении памяти от указателей на массивы вылетает ошибка: _BLOCK_TYPE_IS_VALID(phead->nBlockUse)
Код: #include &lt;iostream&gt; #include &lt;iomanip&gt; #include &quot;float.h&quot; using namespace std; void decShellSort(float *arr, int...

phead->nblockuse
помогите нейтрализовать ошибку. есть структура struct tim{ WORD wMonth; WORD wDay; WORD wYear; WORD wHour; WORD...


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

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Новые блоги и статьи
Генерация OpenQASM из кода Q#
EggHead 10.07.2025
Летом 2024-го я начал эксперименты с библиотекой Q# Bridge, и знаете что? Она оказалась просто находкой для тех, кто работает на стыке разных квантовых экосистем. Основная фишка этой библиотеки -. . .
Изучаем новый шаблон ИИ-чата .NET AI Chat Web App
stackOverflow 10.07.2025
В . NET появилось интересное обновление - новый шаблон ИИ-чата под названием . NET AI Chat Web App. Когда я впервые наткнулся на анонс этого шаблона, то сразу понял, что Microsoft наконец-то. . .
Результаты исследования от команды ARP (июль 2025 г.)
Programma_Boinc 10.07.2025
Результаты исследования от команды ARP (июль 2025 г. ) Африканский проект по дождям (ARP) World Community Grid снова запущен! Мы рады поделиться обновленной информацией о нашем прогрессе с осени. . .
Angular vs Svelte - что лучше?
Reangularity 09.07.2025
Сегодня рынок разделился на несколько четких категорий: тяжеловесы корпоративного уровня (Angular), гибкие универсалы (React), прогрессивные решения (Vue) и новая волна компилируемых фреймворков. . .
Code First и Database First в Entity Framework
UnmanagedCoder 09.07.2025
Entity Framework дает нам свободу выбора, предлагая как Code First, так и Database First подходы. Но эта свобода порождает вечный вопрос — какой подход выбрать? Entity Framework — это. . .
Как использовать Bluetooth-модуль HC-05 с Arduino
Wired 08.07.2025
Bluetooth - это технология, созданная чтобы заменить кабельные соединения. Обычно ее используют для связи небольших устройств: мобильных телефонов, ноутбуков, наушников и т. д. Работает она на частоте. . .
Руководство по структурам данных Python
AI_Generated 08.07.2025
Я отчетливо помню свои первые серьезные проекты на Python - я писал код, он работал, заказчики были относительно довольны. Но однажды мой наставник, взглянув на мою реализацию поиска по огромному. . .
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах
Programma_Boinc 08.07.2025
Тестирование энергоэффективности и скорости вычислений видеокарт в BOINC проектах Опубликовано: 07. 07. 2025 Рубрика: Uncategorized Автор: AlexA Статья размещается на сайте с разрешения. . .
Раскрываем внутренние механики Android с помощью контекста и манифеста
mobDevWorks 07.07.2025
Каждый Android-разработчик сталкивается с Context и манифестом буквально в первый день работы. Но много ли мы задумываемся о том, что скрывается за этими обыденными элементами? Я, честно говоря,. . .
API на базе FastAPI с Python за пару минут
AI_Generated 07.07.2025
FastAPI - это относительно молодой фреймворк для создания веб-API, который за короткое время заработал бешеную популярность в Python-сообществе. И не зря. Я помню, как впервые запустил приложение на. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru