удалить повреждение кучи указателей массива

Я получаю исключение в этой строке в Visual Studio 2015. Сборка выполняется без ошибок.

_free_dbg(block, _UNKNOWN_BLOCK);

Вот как я объявляю новый массив указателей:

CAirship * pAirShip[10];

Вот как я удаляю массив указателей pAirShip:

for (int i = 0; i < 10; i++) {
            if (pAirShip[i]) {
            cout << "pAirShip[" << i << "] is " << pAirShip[i] << endl;
            delete pAirShip[i];// Delete appropriate object
    }
        } // end for loop

Я получаю сообщение об ошибке при попытке delete pAirShip[0],

Вот окно отладки, которое печатает адреса указателей:

введите здесь описание изображения

Вот полный код:

struct AirShipFile {
    int Type;  // Airplane or Balloon
    string name;        // Name of the airship
    int passCount;      // passenger count
    int weightCargo;     // cargo weight
    int EngOrGas;       // engine or gas type
    int distance;       // range or altitude
};
enum EngineType { Jet, Propeller }; // for airplanes only
std::ostream& operator<<(std::ostream& out, const EngineType value) {
static std::map<EngineType, std::string> strings;
if (strings.size() == 0) {
#define INSERT_ELEMENT(p) strings[p] = #p
    INSERT_ELEMENT(Jet);
    INSERT_ELEMENT(Propeller);
#undef INSERT_ELEMENT
    }

return out << strings[value];
}
enum GasType {Helium, Hydrogen };  // for proprellers only
std::ostream& operator<<(std::ostream& out, const GasType value) {
static std::map<GasType, std::string> strings;
if (strings.size() == 0) {
#define INSERT_ELEMENT(p) strings[p] = #p
    INSERT_ELEMENT(Helium);
    INSERT_ELEMENT(Hydrogen);
#undef INSERT_ELEMENT
    }

return out << strings[value];
}
enum AirShipType { AIRPLANE, BALLOON };
class CAirship {
public:
CAirship() { }
virtual void SetData(AirShipFile &data) = 0;
virtual void GetData() = 0;
AirShipType GetAirShipType() { return m_AirShipType; }

protected:
AirShipType m_AirShipType;

};

class CAIRPLANE : public virtual CAirship {
public:
CAIRPLANE() : CAirship() {}
void SetData(AirShipFile &data);
void GetData();

private:
EngineType m_EngineType;
int m_MaxPassengerCount;
string m_Name;
int m_MaxCargoWeight;
int m_MaxAltitude;
};
// Function: SetData
void CAIRPLANE::SetData(AirShipFile &data)
{
// cast integer to enum
m_EngineType = EngineType(data.EngOrGas);
// airplane name
m_Name = data.name;
// passenger count
m_MaxPassengerCount = data.passCount;
//max cargo weight
m_MaxCargoWeight = data.weightCargo;
// cast integer to enum
m_AirShipType = AirShipType(data.Type);
// maximum altitude
m_MaxAltitude = data.distance;

}
void CAIRPLANE::GetData()
{
cout << setw(20) << m_Name << "\t" << setw(20) << m_EngineType << setw(20);
cout << left << setw(20) << m_MaxAltitude << "\n";
}
class CBALLOON : public virtual CAirship {
public:
CBALLOON() : CAirship() {}
void SetData(AirShipFile &data);
void GetData();

private:
GasType m_GasType;
EngineType m_EngineType;
int m_MaxPassengerCount;
string m_Name ;
int m_MaxCargoWeight;
int m_MaxAltitude;
};
void CBALLOON::SetData(AirShipFile &data)
{
// cast integer to enum
m_GasType = GasType(data.EngOrGas);
// airplane name
m_Name  = data.name;
// passenger count
m_MaxPassengerCount = data.passCount;
//max cargo weight
m_MaxCargoWeight = data.weightCargo;
// cast integer to enum
m_AirShipType = AirShipType(data.Type);
// maximum altitude
m_MaxAltitude = data.distance;
}
void CBALLOON::GetData()
{
cout << setw(20) << m_Name << "\t" << setw(20)<< m_GasType << setw(20);
cout << left << setw(20) << m_MaxAltitude << "\n";
}
// AIRPLANE = 0
// BALLOON = 1
int main(int argc, char *argv[])
{
if (argc != 2) {
    cout << "Usage: PR <filename>\n";
    return 1;
}
ifstream Infile(argv[1]);
if (!Infile) {
    cout << "Cannot open file\n";
    return 1;
}
char LineBuf[100];
char d[] = ",";
CAirship * pAirShip[10];
int i = 0;
while (Infile.getline(LineBuf, 100)) {
    struct AirShipFile data;
    // read the first field Airship type
    // airplane or balloon
    data.Type = atoi(strtok(LineBuf, d));
    switch (data.Type) {
    case AIRPLANE:
        // Create AIRPLANE Object
        pAirShip[i] = new CAIRPLANE();
        data.name = strtok(NULL, d);
        data.passCount = atoi(strtok(NULL, d));
        data.weightCargo = atoi(strtok(NULL, d));
        data.EngOrGas = atoi(strtok(NULL, d));
        data.distance = atoi(strtok(NULL, d));
        break;
    case BALLOON:
        // Create BALLOON Object
        pAirShip[i] = new CBALLOON();
        data.name = strtok(NULL, d);
        data.passCount = atoi(strtok(NULL, d));
        data.weightCargo = atoi(strtok(NULL, d));
        data.EngOrGas = atoi(strtok(NULL, d));
        data.distance = atoi(strtok(NULL, d));
        break;
    default:
        break;
    } // end switch
      // call appropriate function
    pAirShip[i++]->SetData(data);
    memset(LineBuf, '\0', 100);
    }
    Infile.close();
    cout << "Listing of all Airplanes \n";
    cout << left << setw(20) << "\nName" << left<< setw(20)<<"\tEngine     Type";
    cout << left<<setw(20)<<"\Maximum Range" << "\n\n";
    for (int i = 0; i < 10; i++) {
    if (pAirShip[i]->GetAirShipType() == AIRPLANE)

        pAirShip[i]->GetData();
    }
    cout << "\n\nListing of all Balloons \n";
    cout <<left << setw(20) << "\nName" << left << setw(20) << "\tGas Type" ;
    cout << left << setw(20) << "\Maximum Altitude" << "\n\n";
    for (int i = 0; i < 10; i++) {
    if (pAirShip[i]->GetAirShipType() == BALLOON)
        pAirShip[i]->GetData();
    }

for (int i = 0; i < 10; i++) {
    if (pAirShip[i]) {

        delete pAirShip[i];// Delete appropriate object
        }
} // end for loop

return 0;
}

person James    schedule 10.09.2016    source источник
comment
Как вы его распределяете?   -  person Jezor    schedule 10.09.2016
comment
Вы delete указатели, которые вы выделили с помощью operator new. У вас есть статический массив указателей с автоматическим хранением.   -  person DeiDei    schedule 10.09.2016


Ответы (1)


Проблема в том, что при размещении массива любого типа C++ не инициализирует элементы, а оставляет их со «случайными» значениями. Таким образом, когда вы создаете массив указателей, указатели не создаются со значением NULL, nullptr или 0, так что это плохой показатель, если они действительно не используются сами по себе. Попытка освободить место, которое не выделено, вызывает ошибку. Вы должны сначала инициализировать их (самостоятельно в цикле for) с помощью nullptr сразу после создания массива, затем вы можете использовать свой код для удаления массива указателей.

person np_6    schedule 10.09.2016
comment
Большое спасибо! Я установил указатели на nullptr прямо перед тем, как удалить их. Оно работает! Вот что я добавил: pAirShip[i] = nullptr;‹------- for (int i = 0; i ‹ 10; i++) { if (pAirShip[i]) { pAirShip[i] = nullptr; delete pAirShip[i];// Удалить соответствующий объект } } // конец цикла - person James; 12.09.2016
comment
Я упоминаю следующее: CAirship * pAirShip[10]; for(int i=0; i‹10; i++)pAirChip[i]=nullptr; // ваш код для обработки CAirship-ов // ваш код для удаления динамически размещаемых CAirships (первый) То, что вы делаете в своем коде в комментарии, это не правильное удаление динамически размещаемых CAirship-ов, а установка указателей к nullptr, а затем с помощью оператора удаления для указателя nullptr, который не имеет никакого эффекта (выделенная память остается выделенной). Вы должны использовать свой первый код для удаления указателей, но с добавлением одной строки, как я объяснил выше. - person np_6; 12.09.2016
comment
Peja, я получил ошибку после инициализации указателей на ноль. Я добавил полный код. - person James; 14.09.2016
comment
Ошибка возникает при удалении производного класса через указатель базового класса, когда деструктор базового класса не является виртуальным — вместо вызова деструктора производного класса вызывается деструктор базового класса, что является ошибкой. Ваш код должен работать, если вы просто добавите 'virtual ~CAirship(){}' в открытый раздел объявления класса CAirship. - person np_6; 14.09.2016