Проблемы с размещением нового оператора

Я понимаю, что оператор placement new позволяет создавать объект в определенном/конкретном месте памяти. Итак, я попробовал это;

#include <iostream>
#include <new>

using namespace std;

struct Any {
    int x;
    string y;
};

int main() {

    string mem1[1];
    int mem2[5];

    Any *p1 = new (mem1) Any;
    Any *p2 = new (mem2) Any;

    p1->y = "Hello";
    //p2->x = 20;

    cout << p1->y << endl;
    //cout << p2->x;

    return 0;
}

Я понял, что я могу установить строку в место, которое я выделил для хранения ровно 1 строки, но я не могу сделать то же самое для целого числа, подобного этому;

int mem2[1];
Any *p2 = new (mem2) Any;
p2->x = 20;

Я получаю сообщение об ошибке переполнения буфера, хотя мне удается показать значение, которое я поместил в это место, которое равно 20;

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

Почему?

Кроме того, с моим полным кодом, показанным выше, я выделил 2 разных места в памяти для хранения 2 объектов, которые позволяют p1->y печатать без каких-либо проблем. Но когда я уменьшаю это местоположение

int mem2[5]; на любое число ниже 5, которое, я думаю, не имеет ничего общего с местом, где я поместил строку и попытаюсь напечатать строку, я получаю ошибку ошибки сегментации. Почему >= 5? Это связано с доступной памятью?

Есть ли способ проверить успешность использования оператора placement new для размещения объекта в определенном месте памяти?


person Paa K    schedule 08.11.2016    source источник
comment
Похоже, у вас будут серьезные проблемы с выравниванием памяти при размещении new'ing Any в массиве string или int   -  person AndyG    schedule 08.11.2016
comment
Вы должны убедиться, что объект Any помещается в пространство, в которое вы пытаетесь его поместить. mem1 определенно слишком мал. Другая проблема заключается в том, что деструктор для строки вызывается в конце ее области видимости, поэтому вам придется восстанавливать mem1 до конца main.   -  person Bo Persson    schedule 08.11.2016
comment
Кроме того, большинство компиляторов достаточно сообразительны, чтобы преобразовать x = 20; cout << x; просто в cout << 20; и не записывать ничего в x. Так что это не очень хороший тест на работоспособность.   -  person Bo Persson    schedule 08.11.2016
comment
Успешное размещение new гарантировано, если только конструктор не выдает исключение или вы не провоцируете поведение undefined. Если конструктор бросает вызов, вы можете просто catch его, и неопределенное поведение не может быть обнаружено по определению.   -  person Mark Ransom    schedule 08.11.2016
comment
@BoPersson Я не получаю никаких ошибок, говорящих о том, что Any объект не помещается в mem1, поэтому он работает нормально. Когда я уменьшаю «mem2» до любого числа ниже 5, я получаю ошибки при попытке напечатать то, что находится в mem1. Вот почему я в замешательстве!   -  person Paa K    schedule 08.11.2016
comment
@NanaOsaberima, нет никакой гарантии, что если вы переопределите память, вы это заметите, поэтому вам нужно понять, как это работает, а не гадать.   -  person Slava    schedule 08.11.2016


Ответы (1)


В вашем коде есть наборы Undefined Behavior. Во-первых, нет никакой гарантии, что объявление string mem[1]; выделяет достаточно памяти для размещения объекта типа Any....

Во-вторых, даже если у первого было достаточно памяти для хранения такого объекта, деструктор массива string mem[1]; все равно будет запускаться в конце main, но вы перезаписали этот массив чем-то другим, поэтому ваша программа в лучшем случае должна рухнуть.

Вы можете использовать тип POD, например char mem1[sizeof(Any)], для хранения объекта, таким образом, вы уверены, что mem1 достаточно способен хранить Any, и у вас не будет проблем с деструктором mem1, вызываемым в конце main().

Опять же, вы можете изучить стандартное средство для такого рода вещей, std::aligned_storage

person WhiZTiM    schedule 08.11.2016
comment
Вот почему я спросил, есть ли способ проверить успешность размещения нового - person Paa K; 08.11.2016
comment
@NanaOsaberima, основная задача размещения new - вызвать конструктор ... И это единственный способ заставить среду выполнения C ++ создать объект в определенном месте. Ваш вопрос похож на вопрос, как узнать, был ли конструктор объекта успешно вызван при объявлении в стеке. - person WhiZTiM; 08.11.2016
comment
Размещение new гарантируется успешно тогда и только тогда, когда: вызываемый конструктор не генерирует исключение, и у вас есть все права на всю память, необходимую для хранения такого объекта - person WhiZTiM; 08.11.2016