Запрос конкретного адреса для нового оператора - PullRequest
0 голосов
/ 22 марта 2012

Скажите, что я хочу выделить массив целых чисел.

int* array = new int[5];

, а затем предположим, что у меня есть 5 указателей int, все из которых указывают на 5 различных целых чисел массива.

 int* v1 = &array[0];
 int* v2 = &array[1]; //etc..etc

Теперь, когда я «запомнил» расположение всех целых чисел в массиве, я хотел бы управлять элементами как отдельными целыми числами. Так что в теории, если я тогда установлю свой указатель массива на NULL ...

array = NULL;

В теории мне не о чем беспокоиться, потому что все мои указатели v1 и v2 указывают на все элементы в массиве. Проблема в том, скажем, что я сделал с v2. Поэтому я хотел бы удалить v2, чтобы освободить эти 4 байта.

delete v2;

К сожалению, когда я пытаюсь это сделать, случаются плохие вещи. Я предполагаю, потому что таблица распределения памяти говорит: «Эй, вы не можете удалить в этом пространстве, потому что в настоящее время он принадлежит к части массива int!»

Так вот, я бы хотел сказать

delete [] array;

но если я это сделаю, я хочу убедиться, что когда я это сделаю ...

int* v1 = new int;

Я хочу гарантировать, что вновь выделенное целое число было создано по адресу массива [0]. Так есть ли способ указать, где создается новое значение? Или можно как-то контролировать список памяти?

Я попытался использовать оператор размещения, вызвав что-то вроде ...

int* v1 = new((void*)&array[0]) int;

но потом, когда я удаляю массив с помощью оператора delete, а затем пытаюсь получить доступ к v1, разыменовав его ... скажем

cout<<*v1;

Я получаю на экран кучу текста с надписью «двойное освобождение или повреждение (fasttop): ...

Я использую Ubuntu 11.04 и компилятор g ++ в кодовых блоках.

Кроме того, только к вашему сведению, я смотрел на Создать новый объект C ++ по определенному адресу памяти? и именно здесь я получил информацию об операторе размещения, но, похоже, он работает не так, как я нужно, чтобы оно работало.

#include <iostream>

using namespace std;

int main()
{
int *array = new int[20];

for(int i=0;i<4;i++)
{
    array[i] = i;
}

int* a = new ((void*)&array[0]) int;
int* b = new ((void*)&array[1]) int;
int* c = new ((void*)&array[2]) int;
int* d = new ((void*)&array[3]) int;
int* e = new ((void*)&array[4]) int;

cout<<*a<<endl;
cout.flush();

delete[] array;

cout<<*a;

delete a;
delete b;
delete c;
delete d;
delete e;

return 0;
}

Ответы [ 3 ]

0 голосов
/ 22 марта 2012

Распределение памяти не работает так, как вы использовали, и вы не можете освободить память так, как вы пытаетесь.

Размещение new "создает" объект в данном месте, вызывая конструктор объекта, но не выделяет память, и, следовательно, память, используемая для размещения new, не может быть освобождена удалением. Память должна быть предварительно выделена перед вызовом размещения new, и память может быть освобождена в зависимости от того, как было выполнено предварительное распределение.

Использование: Размещение новых . Также я нашел пример из блога (не моего): Место размещения новое

0 голосов
/ 22 марта 2012
delete v2;

Не следует удалять элементы, индивидуально выделенные при размещении новых, освобождайте всю память за один раз, когда закончите с ней, например, delete [] array; (для более подробного объяснения ).

И обновление вашего кода:

#include <iostream>

using namespace std;

int main()
{
    int *array = new int[20];

    for(int i=0;i<5;i++) // Still leaves garbage in rest of array
    {
        array[i] = i; 
    }

    int* a = new (array) int; 
    // int* a = new(&array[0]) int;
    int* b = new (array + 1) int;
    int* c = new (array + 2) int;
    int* d = new (array + 3) int;
    int* e = new (array + 4) int;

    cout << *a << " " << *b << " " << *c << " " << *d << " " << *e << endl;

    delete[] array;
 }

Пара указателей:

1) cout.flush(); не требуется, поскольку std::endl уже вызывает flush().

2) Я не вижу причин, по которым здесь следует использовать новое размещение, взгляните на этот вопрос , чтобы узнать, почему вы должны его использовать. В приведенном выше примере все в порядке int array[5]; и int* a = array;. Кроме того, в связанном списке идея заключается в том, что элементы могут быть легко вставлены и удалены, если вы выделяете массив, вы не можете удалить массив и ожидать, что сможете использовать память впоследствии (это приведет к UB). Таким образом, вы должны выбирать между использованием массива или связанного списка, у вас не может быть обоих (ну, вы могли бы имитировать связанный список в определенной степени).

3) Как я уже упоминал выше, звоните delete [] array; после того, как вы закончили использовать память, и не разыменовывайте указатели в эту память или вызывайте delete для указателей в эту память, как только вы освободите память.

0 голосов
/ 22 марта 2012

коррекция:

int *v1 = array[0];
int *v2 = array[1];

должно быть

int *v1 = array;
int *v2 = array + 1;

Кроме того, если вы выделите new int[5], вы можете освободить память только для всего массива, а не для отдельных элементов.

"Я хочу гарантировать, что вновь выделенное целое число было создано по адресу массива [0]"

Если это так, почему вы должны использовать новое целое число? Просто назначьте array на v1, как показано выше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...