Можете ли вы / как вы можете перераспределить объекты C ++, созданные с размещением new? - PullRequest
2 голосов
/ 06 сентября 2011

У меня есть объект C ++, который создается в плагине в буфере памяти, предоставленном хост-приложением, с оператором размещения new способом, подобным следующему коду:

MyClass* createObject(void* inNewBlock)
{
  MyClass* elementAddr = static_cast<MyClass*>(inNewBlock);
  new (elementAddr) MyClass(); // Placement new into pre-allocated memory
}

Я знаю, что не могу удалить объект, созданный таким образом, но мне было интересно, есть ли способ обнулить память и перераспределить объект на более позднем этапе, если мне это нужно:

void removeObject(MyClass* object)
  memset(object, NULL, sizeof(MyClass));
}

void restoreObject(MyClass* object)
{
  new (object) MyClass(); // Placement new into pre-allocated memory
}

Код выше не работает. Я попробовал это, и приложение хоста зависает или падает, когда я звоню restoreObject(). Я надеялся, что кто-нибудь сможет объяснить мне, почему это не работает и какая альтернатива может быть.

Ответы [ 4 ]

7 голосов
/ 06 сентября 2011

Это слишком запутанно.Вы можете просто уничтожить объект, когда он вам больше не нужен.Кроме того, аргумент place-new уже является пустым указателем, нет необходимости приводить.Это очень похоже на то, что делают стандартные распределители библиотек:

MyClass * create(void * addr)
{
  return ::new (addr) MyClass;    // default-initialize
}
MyClass * create(void * addr, const MyClass & x)
{
  return ::new (addr) MyClass(x); // copy-construct from prototype
}

void destroy(MyClass * p)
{
  p->~MyClass();   // you can now reuse the memory
}

Нет такой вещи, как "восстановление";Вы можете создать новый объект в памяти, который раньше использовался другим объектом, если вы правильно уничтожили этот объект.

Редактировать: Я добавил еще один метод конструирования, который создает копию объекта.заданный объект, если ваш класс не является конструируемым по умолчанию.

4 голосов
/ 06 сентября 2011

Вам нужно вызвать деструктор на объекте перед установкой этой памяти на 0. Например:

void removeObject(MyClass* object)
{
  object->~MyObject();
  memset(object, NULL, sizeof(MyClass);
}

В противном случае объект не освободит свои ресурсы.

Кроме того, нет ничего плохого в том, что вы делаете. Если происходит сбой после изменения вышеупомянутым способом, то это хост-приложение, хранящее что-то, что несовместимо с каждым объектом, и пытается использовать его с другим. Вам нужно будет показать, как он используется в хост-приложении.

2 голосов
/ 06 сентября 2011

Если вы используете новое размещение, вы должны вызвать деструктор напрямую:

MyClass* elementAddr = new (inNewBlock) MyClass();
//Do stuff
elementAddr->~MyClass();
//inNewBlock is now free to be used for other purposes.
0 голосов
/ 06 сентября 2011

Я настоятельно призываю вас указать размер буфера памяти в качестве меры предосторожности, чтобы избежать неприятностей.

Также следует помнить о большой ловушке с новым размещением: выравнивание памяти.См. размещение новых + массив + выравнивание .

Помогает переход в очень большой буфер.

MyClass* createObject(void* inNewBlock, size_t size)
{
  // basic sanity check
  assert(size >= sizeof(MyClass);

  MyClass* result = new (inNewBlock) MyClass(); 

  // result might not be the same as elementAddr
  // check that the result fits in-to the space provided.       
  assert(result + sizeof(MyClass) <= (char*)inNewblock + size);
  return result;
}

Я знаю, что не могу удалить объект, созданный таким образом

На самом деле вы можете (как показано в других ответах):

void deleteObject(MyClass* c) 
{
   c->~MyClass();
}

MyClass* restoreObject(MyClass* c)
{
   return createObject(c, sizeof(MyClass));
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...