новый адрес размещения против необработанного адреса памяти - PullRequest
3 голосов
/ 11 марта 2012

Результат размещения нового всегда кажется таким же, как указатель памяти, который я предоставляю для размещения нового.С GCC это, кажется, справедливо даже для классов с виртуальными функциями, например ...

#include <iostream>
#include <vector>

using namespace std;

class A
{
public:
    int a;
    virtual ~A() {}
};

int main()
{
    void *mem = malloc(sizeof(A));
    A* ptr = new(mem) A();

    cout << "sizeof(T) = " << sizeof(A) << endl;
    cout << "mem = " << mem << endl;
    cout << "ptr = " << ptr << endl;
    cout << "addr a = " << &(ptr->a) << endl;

    ptr->~A();
    free(mem);

    return 0;
}

Вывод этой программы (примечание: 64-разрядная версия Linux) ...

sizeof(T) = 16
mem = 0x1a41010
ptr = 0x1a41010
addr a = 0x1a41018

Гарантирует ли C ++, что mem и ptr идентичны или это просто совпадение GCC?В более крупной портативной программе мне придется сохранять как mem, так и ptr, или я могу просто сохранить один из них и привести его при необходимости?

Чтобы немного прояснить вопрос, я знаю, что распределители памяти иногда помещаютразмер выделенного блока в слове перед указанным блоком памяти.Разрешено ли компиляторам C ++ использовать такие приемы и, скажем, поместить указатель VMT в слове перед блоком памяти, на который указывает указатель объекта?В этом случае mem и ptr будут другими.

Ответы [ 2 ]

4 голосов
/ 11 марта 2012

Да, они одинаковы.Возможно, вы захотите думать об адресе памяти как о пустом указателе, а об адресе объекта - как о типизированном указателе, но если хотите, вы можете привести.В некотором смысле new - это способ «преобразовать» адрес памяти в объект (путем его создания).Вот полная картина (обратите внимание, что нет приведения):

void * addr = std::malloc(sizeof(T));  // or ::operator new(sizeof(T))
T * p = ::new (addr) T;                // "new" gives you an object pointer
p->~T();
std::free(addr);

Хотя это верно только для не-массива версии new.Массив-размещения-новый отличается, и практически непригоден для использования .

Возможно, вы захотите взглянуть на свою реализацию std::allocator, чтобы увидеть размещение-новое и приведение в действие.

1 голос
/ 11 марта 2012

Вы используете void* operator new (std::size_t size, void* ptr) throw(); версию оператора new.Вот что cplusplus.com говорит об этом операторе:

Это версия размещения, которая не выделяет память - она ​​просто возвращает ptr.Обратите внимание, что конструктор для объекта (если он есть) будет по-прежнему вызываться операторным выражением.

Так что это означает, что mem и ptr всегда будь одинаковым.Я думаю, что это плохая идея оставить их обоих, и лучше использовать void* operator new (std::size_t size) throw (std::bad_alloc); версию оператора new, например, в вашем случае: A* ptr = new A;;

...