Форум программистов, компьютерный форум CyberForum.ru

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 11, средняя оценка - 4.64
zahvad
0 / 0 / 0
Регистрация: 22.07.2014
Сообщений: 8
#1

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

22.07.2014, 22:14. Просмотров 1700. Ответов 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";
}
Все необходимые заголовочные файлы подключены. Помогите пожалуйста решить проблему. Конечно, можно было бы пропустить эту ошибку и изучать язык дальше. Но так не интересно.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
22.07.2014, 22:14     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error"
Посмотрите здесь:
При вызове delete[] _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) C++
C++ Ошибка C2676 бинарный "[": "matr" не определяет этот оператор
C++ Error C2143: синтаксическая ошибка: отсутствие ";" перед "строка"
C++ error C2143: синтаксическая ошибка: отсутствие "]" перед ";"
C++ Error C2143: синтаксическая ошибка: отсутствие ";" перед "*"
C++ error C2143: синтаксическая ошибка: отсутствие ";" перед "using"
Error C2143: синтаксическая ошибка: отсутствие ";" перед "<<" C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
IIARTEMII
20 / 20 / 3
Регистрация: 14.06.2012
Сообщений: 95
Завершенные тесты: 1
22.07.2014, 22:32     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #2
Вообще-то всё нормально, это распространённая ошибка MSVS. Где конкретно показывает ошибку, в стандартных файлах? решается переустановкой студии/перезапуском студии/рестарт винды/переход на новую версию студии
zahvad
0 / 0 / 0
Регистрация: 22.07.2014
Сообщений: 8
22.07.2014, 23:00  [ТС]     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #3
Я не совсем понял ваш вопрос. Вот скриншот ошибки:

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

Возможно он подтолкнет вас на какую-нибудь мысль.
Убежденный
Системный программист
Эксперт С++
15247 / 6879 / 1092
Регистрация: 02.05.2013
Сообщений: 11,256
Завершенные тесты: 1
22.07.2014, 23:24     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #4
Цитата Сообщение от IIARTEMII Посмотреть сообщение
Вообще-то всё нормально, это распространённая ошибка MSVS.
Стыдно должно быть писать такую ересь.

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

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

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

Добавлено через 5 минут
IIARTEMII, вам тоже спасибо за помощь.
Убежденный
Системный программист
Эксперт С++
15247 / 6879 / 1092
Регистрация: 02.05.2013
Сообщений: 11,256
Завершенные тесты: 1
22.07.2014, 23:40     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #7
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;
}
Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error"
А между тем, полиморфное удаление объекта без виртуального деструктора - UB.
IIARTEMII
20 / 20 / 3
Регистрация: 14.06.2012
Сообщений: 95
Завершенные тесты: 1
22.07.2014, 23:50     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #8
Это всё понятно
Теперь у меня вопрос, чтобы не создавать новую тему:
Что это за механизм такой, который реагирует на отсутствие виртуального деструктора, если по сути это приводит к утечке памяти, а не к программной ошибке (да, UB может привести к ошибке, а может и нет, но...)? Почему этот механизм себя проявляет только в MSVS? В других продуктах такого никогда не видел

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

Если схематично представить память, то:
|- - - - Base - - - -| - - Der - - |
при подходе выше, у нас будет:
| - - - - - - - - - - | - - Der - - |
Почему тут ошибка? Или тут немножко всё не так?
Убежденный
Системный программист
Эксперт С++
15247 / 6879 / 1092
Регистрация: 02.05.2013
Сообщений: 11,256
Завершенные тесты: 1
23.07.2014, 01:53     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #9
Цитата Сообщение от 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
При полиморфном удалении объекта, когда базовый класс имеет виртуальный
деструктор, аллокатор всегда получает "правильный" адрес памяти для очистки,
так что проблем, описанных выше, не возникает.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
23.07.2014, 04:32     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error"
Еще ссылки по теме:
C++ При вызове деструктора вылазит ошибка _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
C++ При вызове деструктора выдается ошибка _BLOCK_TYPE_IS_VALID (pHead->nBlockUse)
C++ _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
C++ Деструктор и _Block_Type_Is_Valid (pHead->nBlockUse)
C++ Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

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

Или воспользуйтесь поиском по форуму:
uglyPinokkio
326 / 229 / 41
Регистрация: 30.05.2014
Сообщений: 682
23.07.2014, 04:32     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error" #10
Цитата Сообщение от IIARTEMII Посмотреть сообщение
Что это за механизм такой, который реагирует на отсутствие виртуального деструктора, если по сути это приводит к утечке памяти
Поднимаем глаза и читаем заголовок окна сообщения.
Механизм этот называется MS CRT Debug Library.
При правильном применении очень полезный мехнизм, в том числе и для обнаружения утечек памяти.

http://msdn.microsoft.com/en-us/library/974tc9t1.aspx
http://msdn.microsoft.com/en-us/libr...8vs.80%29.aspx
Yandex
Объявления
23.07.2014, 04:32     Оператор "delete" и ошибка "_BLOCK_TYPE_IS_VALID(pHead->nBlockUse) Error"
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru