2010-10-25 9 views
10
SomeObj<unsigned int>* Buffer; 
char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj<unsigned int>)); 
Buffer = new(BufferPtr) SomeObj<unsigned int>[resX*resY]; 

cuando me paso más allá de estas líneas con el depurador, que me muestra los valores de las variables de amortiguación y BufferPtr:colocación nueva gama + + alineación

BufferPtr: 0x0d7f004c 
Buffer: 0x0d7f0050 

Realmente no entiendo por qué esos valores diferir de. Tal como lo entiendo, la colocación nueva debe usar la memoria que comienza en la dirección 'BufferPtr' para inicializar los elementos de la matriz utilizando sus constructores predeterminados en la memoria asignada y devolver un puntero al primer byte del primer elemento de la matriz, que debería ser exactamente el mismo byte que se pasó al nuevo operador de ubicación.

¿He entendido algo mal o alguien me puede decir por qué los valores son diferentes?

gracias!

// editar: bien - he investigado la cuestión y dieron resultados más confusos:

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]; 

el depurador me devuelve los siguientes valores para mis variables:

size: 4 

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

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

por lo que claramente debe tener algo que ver con mi genérico smartpointer clase matth_ptr así que aquí está:

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 
    }; 

}; 

¿Alguien puede explicarme qué está pasando? ¡Gracias!

+0

Fuera de la parte superior de mi cabeza, podría haber alineación o espacio en la VTable. –

+0

¿significa eso que la colocación nueva crea un objeto simplemente en una dirección de memoria más alta si no le gusta la alineación de la dirección pasada? – Mat

+0

Sospecho que sí, aunque no estoy seguro. Una forma de probarlo sería ver si esto sucede en la ubicación de la memoria seleccionada (es decir, forzar giveMeSomeBytes para dar una dirección alineada). –

Respuesta

5

Está utilizando la versión de matriz del operador new que en su implementación está almacenando información sobre el tamaño de la matriz en los primeros bytes de la asignación de memoria.

+0

y cuándo es la versión del nuevo operador que almacena esos bytes y cuándo no lo está haciendo ? por favor revisa mi prueba extendida en la pregunta original. resulta que con el tipo 'int' la dirección no está activa, pero con mi propio objeto sí lo está. – Mat

+0

Si el tamaño de la matriz se almacena depende de si el tipo de objeto tiene un destructor, porque el operador delete [] tendrá que llamar al destructor para cada objeto. – Timo

+0

Entonces, para los objetos que tienen un destructor uno tiene que asignar realmente 4 extrabytes más para no tener problemas. ¿Por qué los tutoriales que discuten asignación de matriz con ubicación nueva no mencionan esto? suena significativo para mí ... – Mat

13

Tenga cuidado con la colocación nueva en las matrices. En el aspecto estándar actual para la sección 5.3.4.12, se encuentra esta:

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

Es claro que va a esperar que el nuevo operador la colocación asignarlo espacio adicional más allá de lo contenido de la matriz necesitan. "y" se especifica solo como un valor integral no negativo. A continuación, compensará el resultado de la nueva función con esta cantidad.

Consulte también 18.4.1.3.4 donde dice que el nuevo operador de ubicación simplemente devuelve el puntero proporcionado. Esta es obviamente la parte esperada.

Basado en 5.3.4.12, dado que ese desplazamiento puede ser diferente para cada invocación de la matriz, la norma básicamente significa que no hay forma de asignar la cantidad exacta de tamaño necesaria. En la práctica, ese valor es probablemente constante y podría agregarlo a la asignación, pero su cantidad puede cambiar por plataforma, y ​​nuevamente, por invocación, como dice la norma.

+11

así que básicamente esto significa que, en lo que respecta al estándar, no se puede usar la ubicación nueva en matrices – Mat

+0

In términos de matrices preasignadas del tamaño exacto: sí. Recuerde que aún puede crear un asignador de ubicación personalizado que funcione más como un asignador dinámico en un bloque de memoria más grande. –

+0

Tenga en cuenta que 'operator new [] (sizeof (T) * 5 + y, 2, f)' es una ** función de asignación de ubicación definida por el usuario **, mientras que 'operator new [] (sizeof (T) * 5, ptr) 'es una ** función de asignación de ubicación SIN ASIGNACIÓN **. Lo que se ve aquí es otro f ** k resultante de la generalización descuidada de "The Committee". Espero que esto se elimine a más tardar en 2020. – bit2shift

1

Como han dicho otros, esto se debe a que su implementación C++ almacena el tamaño de la matriz al inicio del búfer que pasa a la colocación de la matriz nueva.

Una solución fácil para esto es simplemente asignar su puntero de matriz al búfer, luego recorrer la matriz y usar la colocación regular (no de matriz) nueva para construir cada objeto en el búfer.

2

@Mat, esta es realmente una gran pregunta. Cuando utilicé la ubicación nueva [], tuve problemas para eliminar el almacenamiento.Incluso si llamo a mi propia ubicación simétrica delete [], la dirección del puntero es no igual que mi nueva ubicación me la devolvió []. Esto hace que la ubicación nueva [] sea completamente inútil, como ha sugerido en los comentarios.

La única solución que he encontrado fue sugerida por Jonathan @: en lugar de la ubicación nueva [], use la ubicación nueva (no la matriz) en cada uno de los elementos de la matriz. Esto está bien para mí ya que almaceno el tamaño yo mismo. El problema es que tengo que preocuparme por las alineaciones de puntero para los elementos, lo que se supone que debe hacer [] para mí.

+1

No existe el operador de eliminación de ubicaciones. La función delete * de ubicación se llama cuando el constructor lanza dentro del operador new de ubicación y no hace absolutamente nada. Tenga en cuenta que los nuevos operadores de colocación 'void *' están destinados a construir objetos en una región de memoria dada, no a asignar memoria desde el montón. Como tal, * NO PUEDE * utilizar operadores 'borrar' o' eliminar [] 'en una región construida con una nueva matriz de ubicación, necesita mantener la longitud de la matriz (¿suena familiar?) Y recorrer la matriz y llamar a cada destructor. – bit2shift