оператор удаления, выбрасывающий исключение с размещением нового - PullRequest
0 голосов
/ 03 сентября 2018

Я пытаюсь понять оператора нового и размещения нового. Это мой код:

#include<iostream>
using namespace std;

class simpleClass
{
    int objID;

public:
    simpleClass(int ID)     // constructor
    {
        objID = ID;
        cout << "Constructing object with ID: " << objID << endl;
    }

    void printID()
    {
        cout << "Object ID: " << objID << endl;
    }

    ~simpleClass()
    {
        cout << "Destructing object with ID: " << objID << endl;
    }
};

int main(int argc, char** argv)
{

    void *ptrToMem = operator new(sizeof(simpleClass)*3);              
    simpleClass *simpleClassPtr_1 = new (ptrToMem)simpleClass(1); 
    simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + sizeof(simpleClass))simpleClass(2);
    simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + sizeof(simpleClass)*2)simpleClass(3);

    simpleClassPtr_1->printID();
    simpleClassPtr_2->printID();
    simpleClassPtr_3->printID();

    simpleClassPtr_1->~simpleClass();
    simpleClassPtr_2->~simpleClass();
    simpleClassPtr_3->~simpleClass();
    operator delete(ptrToMem);

    return 0;
}

Я просто пытаюсь выделить память для 3 объектов, а затем вызываю новые для них. Кажется, что все работает нормально, пока оператор delete, где он дает мне исключение (в VS2013).

Что я делаю не так? Разрешено ли вызывать оператор удаления при использовании нового размещения?

Ответы [ 3 ]

0 голосов
/ 03 сентября 2018

Проблема здесь в использовании указателей.

Эти две строки неверны:

simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + sizeof(simpleClass))simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + sizeof(simpleClass)*2)simpleClass(3);

Это должно быть так:

simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + 1)simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + 2)simpleClass(3);

Поскольку указатель увеличивается на единицу, адрес увеличивается на размер указанного объекта, поэтому дополнительная sizeof не требуется. Вы превысили диапазон выделенного объема памяти, поэтому он завершился сбоем.

0 голосов
/ 03 сентября 2018

Вы испортили арифметику указателя:

simpleClass *simpleClassPtr_2 = new ((simpleClass*)ptrToMem + sizeof(simpleClass))simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((simpleClass*)ptrToMem + sizeof(simpleClass)*2)simpleClass(3);

Вы выполняете размещение нового на неправильном элементе. Вместо инициализации смежного simpleClass вы создаете число простого класса sizeof(simpleClass). Самое простое - заменить кастинг на char * casting:

simpleClass *simpleClassPtr_2 = new ((char*)ptrToMem + sizeof(simpleClass))simpleClass(2);
simpleClass *simpleClassPtr_3 = new ((char*)ptrToMem + sizeof(simpleClass)*2)simpleClass(3);

Это работает как с GCC, так и с Clang.

0 голосов
/ 03 сентября 2018

Вы получаете доступ к выделенному хранилищу за пределами:

(simpleClass*)ptrToMem + sizeof(simpleClass)

Это должно быть просто + 1. Помните, что арифметика указателей в любом случае работает с шагами размера pointee.

...