Размещение new в памяти, возвращаемое new и new[]

Ниже мой тестовый класс: -

class Base
{
public:
    int data;
    Base(int x) : data(x) {}
};

Теперь я использую новое размещение для создания объектов в уже выделенной памяти: -

ДЕЛО 1:-

void* raw = operator new(4* sizeof(Base));
Base* b = static_cast<Base*>(raw);

for(int i = 0; i < 4; i++)
    new (&b[i]) Base(i);

CASE_2:-

void* raw = operator new[](4* sizeof(Base));  <<<<<<<<<<<<<
Base* b = static_cast<Base*>(raw);

for(int i = 0; i < 4; i++)
    new (&b[i]) Base(i);

В CASE_1 я использовал простое new для выделения достаточного количества памяти, тогда как в Case_2 я использовал new[] для этого выделения. Оба работают нормально, как я тестировал: -

for(int i = 0; i < 4; i++)
{
    Base* b1 = b;
    cout << (*(b1+i)).data;
}

Однако я не понимаю, является ли CASE_1 правильным способом выделения памяти для массива объектов. Оба эти подхода похожи.


person ravi    schedule 07.01.2015    source источник
comment
Правильный способ размещения массивов в C++ — использовать std::vector   -  person Mgetz    schedule 07.01.2015
comment
@Mgetz: Обычно да. Но иногда вы хотите избежать затрат на инициализацию выделенной памяти, и нет (четко определенного) способа сделать это с помощью vector.   -  person Mike Seymour    schedule 07.01.2015
comment
@MikeSeymour Я верю, что на самом деле   -  person Mgetz    schedule 07.01.2015
comment
Если вы просто хотите выделить кусок памяти определенного размера, зачем использовать запутанную функцию operator new вместо использования оператора new[], используя, например, int8_t? Результат будет таким же, но менее запутанным для чтения.   -  person Some programmer dude    schedule 07.01.2015
comment
Кроме того, если у вас есть особые потребности в распределении, вам, вероятно, следует использовать std::vector с настраиваемым распределителем.   -  person Some programmer dude    schedule 07.01.2015
comment
@JoachimPileborg Хорошая идея. Но разве использование new[4] не будет создавать объекты вместе с выделением памяти.   -  person ravi    schedule 07.01.2015
comment
@ravi Нет, если вы выделяете, например. int8_t, как и int8_t* raw = new int8_t[4 * sizeof(Base)];, просто выделяет часть байтов без какой-либо инициализации или построения.   -  person Some programmer dude    schedule 07.01.2015


Ответы (2)


Цитирование этой страницы:

Определение по умолчанию выделяет память, вызывая оператор new: ::operator new (size).

Судя по этому, результат должен быть точно таким же. Обе строки должны возвращать идентичный указатель.

Как отметил @Joachim Pileborg, вам, вероятно, следует избегать operator newи использовать более простой new Base[4].

person Daerst    schedule 07.01.2015

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

Они оба работают.

Использование глобального operator new[] довольно бессмысленно. Все, что он дает вам по сравнению с глобальными operator new, — это возможность для вас (или некоторого другого кода в вашей программе) перегружать их, чтобы делать разные вещи, например, для выделения из разных источников. Таким образом, вы можете счесть несколько лучшей практикой использовать operator new[] для выделения памяти, которая, вероятно, велика, а затем вы могли бы позже оптимизировать для этой цели в другом месте вашей программы. Но это довольно грубый инструмент по сравнению с прямым использованием конкретных распределителей для конкретных целей. Я действительно не думаю, что это распространено, но использование глобального нового вообще не является распространенным явлением.

Кроме того, вы не показываете код для освобождения памяти, поэтому есть много возможностей ошибиться. Как правило, вы должны вызывать деструкторы каждого элемента по очереди, а затем вызывать глобальный оператор удаления, который соответствует новому оператору, который вы использовали. Для вашего конкретного класса Base на самом деле нет никакого вреда в том, что вы не уничтожите его, но если вы пропустите вызовы деструктора и позже измените Base, у вас могут возникнуть проблемы.

person Steve Jessop    schedule 07.01.2015