placement nouveau + tableau + alignement

SomeObj* Buffer; char* BufferPtr = MemoryManager::giveMeSomeBytes(resX*resY*sizeof(SomeObj)); Buffer = new(BufferPtr) SomeObj[resX*resY]; 

Lorsque je dépasse ces lignes avec le débogueur, il me montre les valeurs pour les variables Buffer et BufferPtr:

 BufferPtr: 0x0d7f004c Buffer: 0x0d7f0050 

Je ne comprends pas vraiment pourquoi ces valeurs diffèrent. Si je comprends bien, le placement nouveau devrait utiliser la mémoire commençant à l’adresse ‘BufferPtr’ pour initialiser les éléments du tableau à l’aide des constructeurs par défaut sur la mémoire allouée et renvoyer un pointeur sur le premier octet du premier élément du tableau, qui devrait être exactement le même octet que celui transmis à l’opérateur de nouvel emplacement.

Ai-je bien compris quelque chose qui ne va pas ou quelqu’un peut-il me dire pourquoi les valeurs diffèrent?

Merci!

// edit: ok – j’ai étudié le problème plus en profondeur et obtenu des résultats plus confus:

  int size = sizeof(matth_ptr); 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)); matth_ptr* test3 = new(testPtr3)matth_ptr[a_resX*a_resY]; char* testPtr4 = mmgr::requestMemory(a_resX*a_resY*sizeof(matth_ptr)); matth_ptr* test4 = new(testPtr4)matth_ptr[a_resX*a_resY]; 

le débogueur me renvoie les valeurs suivantes pour mes variables:

 size: 4 testPtr1:0x05100418 test1: 0x05100418 testPtr2:0x0da80050 test2: 0x0da80050 testPtr3:0x05101458 test3: 0x0510145c testPtr4:0x0da81050 test4: 0x0da81054 

il doit donc clairement avoir quelque chose à voir avec ma classe générique de smartpointer matth_ptr alors le voici:

 template  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() {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} X* get() {return ((X*)(mmgr::getBaseAddress(chunkIdx)+(memoryOfst&0x00FFFFFF)));} template matth_ptr(const matth_ptr& other) {memoryOfst=other.memoryOfst;}//put these two operators into the private part in order to prevent copying of the smartpointers template matth_ptr& operator=(const matth_ptr& other) {memoryOfst = other.memoryOfst; return *this;} template 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 }; }; 

Quelqu’un peut-il m’expliquer ce qui se passe? Merci!

Soyez prudent avec le placement nouveau sur les tableaux. Dans la norme actuelle, regardez à la section 5.3.4.12, vous trouverez ceci:

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

Il est clair qu’il s’attendra à ce que l’opérateur de placement nouvel atsortingbut un espace supplémentaire au-delà des besoins du contenu du tableau. “y” est spécifié uniquement en tant que valeur intégrale non négative. Il compensera alors le résultat de la nouvelle fonction par ce montant.

Regardez aussi 18.4.1.3.4 où il est dit que l’opérateur de nouvel emplacement placera simplement le pointeur fourni. C’est évidemment la partie attendue.

Selon 5.3.4.12, étant donné que ce décalage peut être différent pour chaque appel du tableau, le standard signifie qu’il n’ya aucun moyen d’allouer la quantité exacte de taille requirejse. En pratique, cette valeur est probablement constante et vous pouvez simplement l’append à l’allocation, mais son montant peut changer par plate-forme et, encore une fois, par invocation, comme le dit la norme.

Vous utilisez la version de tableau du new opérateur qui, dans votre implémentation, stocke des informations sur la taille du tableau dans les premiers octets de l’allocation de mémoire.

@Mat, c’est en fait une excellente question. Lorsque j’ai utilisé l’emplacement new [], j’ai eu du mal à supprimer le stockage. Même si j’appelle mon propre emplacement symésortingque delete [], l’adresse du pointeur n’est pas la même que celle renvoyée par mon propre emplacement new []. Cela rend le nouveau placement complètement inutile, comme vous l’avez suggéré dans les commentaires.

La seule solution que j’ai trouvée a été suggérée par Jonathan @: au lieu d’utiliser placement new [], utilisez placement new (non-array) sur chacun des éléments du tableau. C’est bien pour moi car je stocke la taille moi-même. Le problème est que je dois m’inquiéter des alignements de pointeur pour les éléments, ce que nouveau [] est censé faire pour moi.

Comme d’autres l’ont déjà dit, cela est dû au fait que votre implémentation C ++ stocke la taille du tableau au début du tampon que vous passez au nouvel emplacement du tableau.

Une solution simple consiste à assigner simplement le pointeur de votre tableau au tampon, puis à le parcourir en boucle et à utiliser un nouvel emplacement (non tableau) pour construire chaque object du tampon.