размещение нового + массив + выравнивание - PullRequest
12 голосов
/ 25 октября 2010
SomeObj<unsigned int>* Buffer;
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>));
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY];

, когда я обхожу эти строки с помощью отладчика, он показывает мне значения переменных Buffer и BufferPtr:

BufferPtr: 0x0d7f004c
Buffer:    0x0d7f0050

Я действительно не понимаю, почему эти значения различаются.Насколько я понимаю, размещение new должно использовать память, начинающуюся с адреса 'BufferPtr', чтобы инициализировать элементы массива с помощью конструкторов по умолчанию в выделенной памяти и вернуть указатель на первый байт первого элемента в массиве, который должен бытьточно такой же байт, который был передан оператору размещения new.

Я что-то понял неправильно или кто-то может сказать мне, почему значения различаются?

спасибо!

// edit: ok - я исследовал проблему дальше и получил более запутанные результаты:

    int size = sizeof(matth_ptr<int>);

    char* testPtr1 = (char*)malloc(a_resX*a_resY*sizeof(int));
    int* test1 = new(testPtr1) int[a_resX*a_resY];

    char* testPtr2 = mmgr::requestMemory(a_resX*a_resY*sizeof(int));
    int* test2 = new(testPtr2) int[a_resX*a_resY];

    char* testPtr3 = (char*)malloc(a_resX*a_resY*sizeof(matth_ptr<int>));
    matth_ptr<int>* test3 = new(testPtr3)matth_ptr<int>[a_resX*a_resY];

    char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr<int>));
    matth_ptr<int>* test4 = new(testPtr4)matth_ptr<int>[a_resX*a_resY];

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

size: 4

testPtr1:0x05100418
test1:   0x05100418
testPtr2:0x0da80050
test2:   0x0da80050

testPtr3:0x05101458
test3:   0x0510145c
testPtr4:0x0da81050
test4:   0x0da81054

, поэтому он явно должен что-тосделать с моим общим классом smartpointer matth_ptr, вот оно:

template <class X> class matth_ptr
{
public:
    typedef X element_type;

    matth_ptr(){
        memoryOfst = 0xFFFFFFFF;
    } 

    matth_ptr(X* p) 
    {
        unsigned char idx = mmgr::getCurrentChunkIdx();
        memoryOfst = (int)p-(int)mmgr::getBaseAddress(idx);
        assert(memoryOfst<=0x00FFFFFF || p==0);//NULL pointer is not yet handled
        chunkIdx = idx;
    }
    ~matth_ptr()                {}
    X& operator*()              {return *((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
    X* operator->()             {return  ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}
    X* get()                    {return  ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));}


    template<typename T>
    matth_ptr(const matth_ptr<T>& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers
    template<typename T>
    matth_ptr& operator=(const matth_ptr<T>& other) {memoryOfst = other.memoryOfst; return *this;}
    template<typename T>
    friend class matth_ptr;
private:

    union //4GB adressable in chunks of 16 MB
    {
        struct{
            unsigned char padding[3]; //3 bytes padding
            unsigned char chunkIdx; //8 bit chunk index
        };
        unsigned int memoryOfst; //24bit address ofst
    };

};

Может кто-нибудь объяснить мне, что происходит?спасибо!

Ответы [ 4 ]

13 голосов
/ 25 октября 2010

Будьте осторожны с размещением новых на массивах.В текущем стандартном взгляде на раздел 5.3.4.12 вы найдете следующее:

new(2,f) T[5] results in a call of operator new[](sizeof(T)*5+y,2,f)

Понятно, что он ожидает, что оператор размещения new выделит ему дополнительное пространство сверх того, что нужно содержимому массива.«y» указывается только как неотрицательное целочисленное значение.Затем он сместит результат новой функции на эту величину.

Также посмотрите 18.4.1.3.4, где говорится, что оператор размещения new просто возвращает предоставленный указатель.Это, очевидно, ожидаемая часть.

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

6 голосов
/ 25 октября 2010

Вы используете версию массива оператора new, который в вашей реализации хранит информацию о размере массива в первых нескольких байтах выделения памяти.

2 голосов
/ 19 июня 2013

@ Мат, это на самом деле отличный вопрос. Когда я использовал размещение new [], у меня были проблемы с удалением хранилища. Даже если я вызову свое собственное симметричное размещение, delete [], адрес указателя будет , а не , такой же, как был возвращен моим собственным местом размещения new []. Это делает размещение новых [] совершенно бесполезным, как вы предложили в комментариях.

Единственное решение, которое я нашел, было предложено Джонатаном @: вместо размещения нового [] используйте размещение нового (не массива) на каждом из элементов массива. Это хорошо для меня, так как я храню размер сам. Проблема в том, что мне нужно беспокоиться о выравнивании указателей для элементов, что new [] должен сделать для меня.

1 голос
/ 19 апреля 2013

Как уже говорили другие, это происходит из-за того, что ваша реализация C ++ хранит размер массива в начале буфера, который вы передаете для размещения массива new.

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

...