Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

Using malloc and free, it is easy to allocate structures with extra data beyond the end. But how do I accomplish the same with new/ delete?

I know I could use placement new syntax along with malloc for the allocation part, but will delete work properly and portably if I place an object in memory allocated by malloc?

What I want to accomplish is the same as the following example, but using new/ delete instead of malloc/ free, so that constructors/destructors will be called properly:

#include <cstdlib>
#include <cstring>
#include <iostream>

class Hamburger {
  int tastyness;
 public:
  char *GetMeat();
};

char *Hamburger::GetMeat() {
    return reinterpret_cast<char *>(this) + sizeof(Hamburger);
}

int main(int argc, char* argv[])
{
   Hamburger* hb;
   // Allocate a Hamburger with 4 extra bytes to store a string.
   hb = reinterpret_cast<Hamburger*>(malloc(sizeof(Hamburger) + 4));
   strcpy(hb->GetMeat(), "yum");
   std::cout << "hamburger is " << hb->GetMeat() << std::endl;
   free(hb);
}

Output: hamburger is yum

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
190 views
Welcome To Ask or Share your Answers For Others

1 Answer

You can do this without resorting to malloc/free or undefined behavior (I'm not sure about the reinterpret_cast, but at least construction/destruction can be done just fine).

To allocate the memory you can just call the global operator new directly. After that you use good old placement new to construct the object there. You have to guard the ctor-call though, since the "placement delete" function that's called if the ctor fails will not release any memory but just do nothing (just as placement new does nothing).

To destroy the object afterwards you can (and may) call the destructor directly, and to release the memory you can call the global operator delete.

I think it should also be OK to just delete it as you would any normal object, since calling the destructor and global operator delete afterwards is just what the normal delete will do, but I'm not 100% sure.

Your example modified like that:

#include <cstdlib>
#include <cstring>
#include <iostream>

class Hamburger {
    int tastyness;
public:
    char *GetMeat();
};

char *Hamburger::GetMeat() {
    return reinterpret_cast<char *>(this) + sizeof(Hamburger);
}

int main(int argc, char* argv[])
{
    Hamburger* hb;
    // Allocate space for a Hamburger with 4 extra bytes to store a string.
    void* space = operator new(sizeof(Hamburger) + 4);
    // Construct the burger in that space
    hb = new (space) Hamburger; // TODO: guard ctor call (release memory if ctor fails)
    strcpy(hb->GetMeat(), "yum"); // OK to call member function on burger now

    std::cout << "hamburger is " << hb->GetMeat() << std::endl;

    // To delete we have to do 2 things
    // 1) call the destructor
    hb->~Hamburger();
    // 2) deallocate the space
    operator delete(hb);
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...