C ++: сохранить экземпляр класса в выделенной памяти - PullRequest
3 голосов
/ 08 декабря 2010

У меня есть класс A. Некоторая библиотека, которую я использую, выделяет мне определенное количество памяти, sizeof, и возвращает на нее пустой указатель.

A* pObj = (A*) some_allocator_im_forced_to_use( sizeof A );

Теперь, как я могу создать новый экземпляр A в только что выделенной памяти?

Я пробовал это с:

*pObj = A();

Но это не сработало - деструктор был вызван сразу после конструктора A.

Ответы [ 6 ]

8 голосов
/ 08 декабря 2010

Вы можете использовать новое размещение:

A* pObj = new ( some_allocator_im_forced_to_use( sizeof( A ) ) ) A;

Создает новый экземпляр A в местоположении, возвращаемом функцией some_allocator_im_forced_to_use. Эта функция должна возвращать void*, указывающий на достаточное количество памяти, соответствующим образом выровненное для объекта A в рассматриваемой реализации.

Вероятно, вам придется вручную вызывать деструктор для этого объекта вручную, поскольку вы не сможете использовать обычный delete pObj для его уничтожения.

pObj->~A();
// Call custom allocator's corresponding deallocation function on (void*)pObj

Чтобы правильно уничтожить объект и освободить память, вы можете рассмотреть возможность использования shared_ptr с пользовательским средством удаления.

3 голосов
/ 08 декабря 2010

Использовать размещение new:

new (pObj) A;

Вам также нужно будет по-разному уничтожить объект, поскольку delete предполагает (неправильно), что вы создали объект с простой старой new:

pObj->~A();
some_deallocator_im_forced_to_use( pObj );
2 голосов
/ 08 декабря 2010

Вам нужно «новое размещение»

См. Этот ответ: Какие варианты использования для "размещения новых"?

1 голос
/ 08 декабря 2010

Некоторые люди выступают за размещение новых.

Это опасно, и пока в двух примерах использования пропущены важные детали, такие как заголовок <new>, квалификация вызова как ::new ... и способ очисткиup.

Безопасное решение - определить пользовательские функции выделения и освобождения для вашего класса или для класса, производного от вашего класса.Пример ниже показывает последнее.Обратите внимание, что виртуальный деструктор существует только для поддержки деривации классов;если вы не выводите, вам это не нужно.

#include <stddef.h>
#include <iostream>

void* some_allocator_im_forced_to_use( size_t size )
{
    std::cout << "Allocated " << size << " bytes." << std::endl;
    return ::operator new( size );
}

void some_deallocator_im_forced_to_use( void* p, size_t size )
{
    std::cout << "Deallocated " << size << " bytes." << std::endl;
    ::operator delete( p );
}

struct A
{
    int x_;
    A(): x_( 42 ) {}
    virtual ~A() {}
};

struct CustomAllocedA
    : A
{
    void* operator new( size_t size )
    {
        return some_allocator_im_forced_to_use( size );
    }

    void operator delete( void* p, size_t size )
    {
        some_deallocator_im_forced_to_use( p, size );
    }
};

int main()
{
    A* const    p    = new CustomAllocedA;

    std::cout << p->x_ << std::endl;
    delete p;
}

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

Приветствия & hth.,

1 голос
/ 08 декабря 2010
0 голосов
/ 08 декабря 2010

Если ваш распределитель следует модели std::allocator, он должен иметь несколько методов:

  • allocate
  • construct
  • destroy
  • deallocate

Они в значительной степени говорят сами за себя, важно то, что вы несете ответственность за их вызов:

  • в правильном порядке
  • и не забывайте

, иначе вы либо получите UB, либо утечку.

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

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