B works, A does not. Is there any way to make A work without using new (that includes placement new)? The code is more or less identical and I'm sure my overloaded new/delete are being called. The only difference is that A doesn't call the constructor but that shouldn't matter since it's empty (?).

I'm guessing it has something to do with vtables but I'm not sure how to fix it (if at all possible).

A:

#include <stdio.h>
#include <stdlib.h>

struct ishazbot {
    virtual void do_stuff(void) = 0;
};

class shazbot : public ishazbot
{
    public:
        shazbot() {}
        ~shazbot() {}

        void do_stuff(void) { printf("SHAZBOT!\n"); }
};

int main(void)
{
    ishazbot* sb = (ishazbot*)malloc(sizeof(shazbot));
    sb->do_stuff();
    free(sb);

    return 0;
}

B:

#include <stdio.h>
#include <stdlib.h>

void* operator new(size_t size) { return malloc(size); }
void operator delete(void* p) { free(p); }

struct ishazbot {
    virtual void do_stuff(void) = 0;
};

class shazbot : public ishazbot
{
    public:
        shazbot() {}
        ~shazbot() {}

        void do_stuff(void) { printf("SHAZBOT!\n"); }
};

int main(void)
{
    ishazbot* sb = (ishazbot*)new shazbot();
    sb->do_stuff();
    delete sb;

    return 0;
}

Recommended Answers

All 13 Replies

Is there any way to make A work without using new (that includes placement new)?

No, non-POD classes can not be allocated dynamically without using new. As far as the standard is concerned, it's undefined behavior to not use new.

In practice the problem is, as you suspected, the vtable. malloc returns uninitialized memory, so the object's vtable pointer will point somewhere random instead of to shazbot's vtable.

May I ask why you want/need to avoid using new?

PS: You shouldn't use explicit casts to perform an upcast. That makes it harder to see when you perform a cast that's actually unsafe. Also you should prefer C++ style casts over C-style casts in the cases where you do need an explicit cast.

Is there any way to make A work without using new (that includes placement new)?

Without using the placement new operator, NO. At least, not in any way that would have defined behavior for any class.

The code is more or less identical and I'm sure my overloaded new/delete are being called.

They are not identical at all. When you overload new/delete, you only control the allocation/deallocation of the memory, you cannot control (or avoid) the call of the constructor. The placement-new performs only the constructor call, and when you overload the new operator, it basically uses your new operator to allocate the memory and then calls the constructor into that memory (e.g., like placement-new). In other words, these two lines are pretty much equivalent:

Foo* pf = new Foo;  // using new

Foo* pf = new ( malloc(sizeof(Foo)) ) Foo;  // using malloc and placement-new.

The only difference is that A doesn't call the constructor but that shouldn't matter since it's empty (?).

It only looks empty. It is not empty. You have a base-class with a virtual function, and thus, it has a virtual table pointer which needs to be initialized. The constructor will initialize this virtual table pointer, if you don't call the constructor it will be left uninitialized, and thus, the call to do_stuff() will crash the program (or be undefined behavior).

I'm guessing it has something to do with vtables but I'm not sure how to fix it (if at all possible).

The way to avoid the problems is to use new, new[] or new() (placement-new), such that the constructors get called. The constructors are important in C++, don't try to work your way around them. For POD-types (no user-defined constructor of any kind, no user-defined destructor, no non-POD data member or base-class, no virtual functions... basically just a C-style struct), then it is OK not to call the constructor, but in that case, the compiler will optimize away the constructor anyways, so you don't have to worry about using new to allocate those objects either. The moral of the story is: ALWAYS USE new/delete IN C++!

That's a bummer. I think the way new works is horrible but there's nothing I can do short of implementing my own vtables with function pointers. Thanks anyway.

I think the way new works is horrible

How so?

How so?

I don't see a valid reason why memory allocation and object construction should be tied together like that. It's taking away control from the programmer and if they continue down that path we'll have another java in a few years.

I don't see a valid reason why memory allocation and object construction should be tied together like that.

In the vast majority of cases it's more convenient (and safer) to do both at once. For the cases where it's not, there's placement new.

if they continue down that path we'll have another java in a few years.

You're talking like new is somehow a new addition to C++. new's been around as long as C++'s been around. It's not a step in C++'s journey to become Java. It predates Java.

In the vast majority of cases it's more convenient (and safer) to do both at once. For the cases where it's not, there's placement new.

It's still horrible syntax, you're doing 2 important things at once but you couldn't tell just by looking at it. As for safety, C style casts worked perfectly fine for ages and now they're suddenly considered bad (same goes for preprocessor). The language was perfectly fine, it's the people that can't handle it causing the problems.

You're talking like new is somehow a new addition to C++. new's been around as long as C++'s been around. It's not a step in C++'s journey to become Java. It predates Java.

C was good, then came OOP and C++ and now they're slowly picking away at it. One day they'll remove pointers because it's more convenient and safer.

I don't see a valid reason why memory allocation and object construction should be tied together like that.

You can't be serious. You can't see a valid reason for initialization to happen right after allocation, and vice versa, for finalization to happen just before deallocation. The reason is simple: you can't do anything with an uninitialized chunk of memory, except initializing it, and similarly for finalization. This is called a deterministic memory model, which is also used in C (and all similar procedural languages, like Fortran or Pascal) and even in assembly! I mean, there's nothing revolutionary about this at all.

It's taking away control from the programmer

It doesn't take any control away, because you control what the constructor does, or you choose to create a POD-type and then it's all the same as in C (except "malloc" is replaced with "new"). The only times that it is valid to not do an initialization (which really means that you do the initialization sometimes later) is when the type is a POD (Plain-Old-Data type), in every other case, it wouldn't be "correct" code not to initialize it almost immediately. This is not about a fuzzy concept of "safety", it's about the very strict concept of "correctness" (i.e., "defined behavior").

and if they continue down that path we'll have another java in a few years.

The new/delete and constructor/destructor mechanism has been an integral part of the C++ language ever since it was created. There's no "down that path", it's part of the starting point. And if you read up a bit on how classes (with public-private-protected data and function members, with virtual functions, single-, multiple- and virtual-inheritance, etc.) are actually constructed in memory and how they function, you'll realize soon enough that, for technical reasons, this automatic tie between allocation and construction is necessary, and that's why it was designed so from the beginning.

And by the way, C++ is considered (by OOP purists) as one of the more backwards programming language because of its deterministic memory model (i.e., the automatic tie of allocation/construction). Other OOP languages, like Java/C# in particular, have non-deterministic models in which the allocation and construction are loosely tied together but there is no determinism in it. So, don't talk too fast about lumping C++ in a similar category as Java/C#.

It's still horrible syntax, you're doing 2 important things at once but you couldn't tell just by looking at it.

You think too much in terms of C. You think that 2 things are happening: "give me a chunk of memory" and "initialize this chunk of memory". In C++, you must think in terms of objects, and in this case, only one thing happens: "give me an object". The syntax fits perfectly with the semantics. A language's syntax has to be consistent with it's own semantics, not that of another language (like C).

As for safety, C style casts worked perfectly fine for ages and now they're suddenly considered bad (same goes for preprocessor).

You might want to read the sections of the C++ standard that pertains to casting operators, it's very enlightning. With inheritance (which doesn't exist in C), there need to be more complicated rules about casting references or pointers. With const-ness (which doesn't exist in C), there needs to be a way to respect that across the casts. And to accomodate all situations, there needs to be very powerful (or overriding) casts too. C++ is a strongly-typed language, C is a weakly-typed language, it's apples and oranges. The only unfortunate thing is that C++ carried over support for C-style casts, however, in many cases they are dangerous in C++ because the simple rules of C casts don't mesh well with the complex requirements of casts in C++ and they can lead to subtle bugs and undefined behavior, please read the relevant section of the C++ standard for more details on that.

The pre-processor is not considered bad. It's just that certain abuses of MACROs and #defines in general, that people were forced to do in C, are generally no longer needed in C++ thanks to certain features (namely templates and overloading). These abuses of MACROs were never and are not considered good practice in C either, people just don't have a choice. Guidelines about using MACROs in your code are not very different much between C to C++, it's just that, in C++, there are more options in the "better alternatives" column.

The language was perfectly fine, it's the people that can't handle it causing the problems.

Many, if not most, of the people who designed C++ (and are still designing it today) were also heavily involved in designing C (and are still designing it today!). Are you saying these people can't handle C? So they created C++? Seriously now, think before you speak (write). I, personally, have no troubles coding in C, no troubles at all, and it is not because I appreciate the value and purpose of the features that C++ brings that I necessarily am just incompetent at coding the same thing in C (just like being able to appreciate the ease of using a chain-saw to cut a tree doesn't imply incompetence or mishandling of an axe).

C was good, then came OOP and C++ and now they're slowly picking away at it. One day they'll remove pointers because it's more convenient and safer.

What are "they" actually picking away from C? Most of the things that C++ doesn't support from C are things that are relatively new to C (C99), or things that are so old that they don't make any sense on any device that is less than 20 years old (like far, near, and auto), which you would never see a C programmer use today.

The focus of the C++ language has always been robustness and performance (btw, "robustness" does not equal "safe", but rather something like "strictly defined behavior"). Convenience is a plus that they try to put in if possible (without breaking robustness or performance). Safety is something that is almost entirely left to the programmer to handle in whichever way he sees fit. For proof that performance is not affected, most benchmarks put C++ dead even with C (not too surprising since most C and C++ compilers share the same back-end).

Generally, I just suggest that you get to know C++ a bit better, because you will understand how consistent it is, but, of course, you have to adopt C++ semantics and stop looking at the code as "C with classes". I wish C++ didn't keep C as a pseudo-sub-set, it lends people to think that C semantics apply to C++ as well, it doesn't, C++ has its own semantics, which are very different from C (but compatible with it).

The only times that it is valid to not do an initialization (which really means that you do the initialization sometimes later) is when the type is a POD (Plain-Old-Data type), in every other case, it wouldn't be "correct" code not to initialize it almost immediately.

It's always valid to allocate memory at one point and then initialize it using placement new much later in the program as long as you don't use the memory in the meantime. And there are cases where this is indeed necessary. For example there's no way to correctly implement std::vector without doing this (at least I can't think of one).

Solved question is solved. But I'm going to throw this in here anyway.

#include <cstdlib>
#include <iostream>
using namespace std;
class A{
private:
    int i;
    int j;
public:
    A(){
        cout<<"Constructor being called!"<<endl;
    }
    ~A(){
        cout<<"Destructor being called!"<<endl;
    }
    int getI(){return i;}
    void setI(int newI){i=newI;}
    int getJ(){return j;}
    void setJ(int newJ){j=newJ;}
    void doesThisWork(){
        cout<<this->i<<"\t"<<this->j<<endl;
    }
};

int main(){
    cout<<"Setting up 'a' object."<<endl;
    A *a=(A*)malloc(sizeof(A)); //Allocate
    new (a) A();    //Call constructor
    a->setI(10);
    a->setJ(20);
    cout<<a->getI()<<"\t"<<a->getJ()<<endl;
    a->doesThisWork();
    a->~A();    //Call destructor
    free(a);    //De-allocate
    cout<<"Done with 'a' object."<<endl;

    cout<<"Setting up 'b' object."<<endl;
    A *b=(A*)malloc(sizeof(A)); //Allocate
    b->setI(9);
    b->setJ(18);
    cout<<b->getI()<<"\t"<<b->getJ()<<endl;
    b->doesThisWork();
    free(b);    //De-allocate
    cout<<"Done with 'b' object."<<endl;
    return 0;
}

Your mileage may vary. On mine (MinGW 32-bit on Windows XP), it worked fine.

Got a little help from here on using new AFTER the class is allocated:
http://stackoverflow.com/questions/2995099/malloc-and-constructors

Your code works because it doesn't contain any virtual functions, so no vtable is required. It's still undefined behavior though (the version without placement new, I mean).

Duly noted. I'm just showing that allocation and initialization can be two seperate steps.
Last code segment from me for this post:

#include <cstdlib>
#include <iostream>
using namespace std;
class C{
public:
    C(){
        cout<<"C's constructor called."<<endl;
    }
    virtual ~C(){
        cout<<"C's destructor called."<<endl;
    }
    virtual void virtualFunction(void)=0;
};

class A:public C{
private:
    int i;
    int j;
public:
    A(){
        cout<<"A's constructor being called!"<<endl;
    }
    ~A(){
        cout<<"A's destructor being called!"<<endl;
    }
    void virtualFunction(void){
        cout<<"A's virtual function!"<<endl;
    }
    int getI(){return i;}
    void setI(int newI){i=newI;}
    int getJ(){return j;}
    void setJ(int newJ){j=newJ;}
    void doesThisWork(){
        cout<<this->i<<"\t"<<this->j<<endl;
    }
};

int main(){
    cout<<"Setting up 'e' object."<<endl;
    C *e=(C*)malloc(sizeof(A)); //Allocate
    new (e) A(); //Call constructor
    ((A*)e)->setI(9);
    ((A*)e)->setJ(18);
    e->virtualFunction();
    cout<<((A*)e)->getI()<<"\t"<<((A*)e)->getJ()<<endl;
    ((A*)e)->doesThisWork();
    ((A*)e)->~A();  //Call destructor
    free(e);    //De-allocate
    cout<<"Done with 'e' object."<<endl;
    return 0;
}

That is some really ugly code. I feel ashamed of myself now.

I'm just showing that allocation and initialization can be two seperate steps.

Yes, if you use placement new, but the OP already knows that. He already mentioned it in the original post (and I emphasized in once or twice in my responses as well).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.