0

Having class A, for example,

class A{
public:
    int x;
    void Update(){
        cout << " from a\n";
    }
};

In order to instantiate an object of A without calling the constructor, it goes like:

A* a = (A*) new char[sizeof(A)];

a->x = 9;
cout << a->x; a->Update(); //"9 from a" is outputted

now In case Update is a virtual function

class A{
public:
    int x;
    virtual void Update(){
        cout << " from a\n";
    }
};

It throw an "Access violation" exception, why ?

Ahmed U3
  • 698
  • 5
  • 9
  • You never constructed an `A`. For the record, it also won't work with the infinite number of other objects you never constructed. Casting isn't constructing *anything*. And to intercept the "but it works with non-virtual functions" followup, usually no vtable-dispatch is needed for said non-virtual invokes. The compiler just emits code that pushes an implicit `this` and fires the function without vtable resolution. Such is not the case with your invoke. – WhozCraig Mar 09 '14 at 09:40
  • In my experience when people are casting they are usually doing something wrong – Ed Heal Mar 09 '14 at 09:44

5 Answers5

3

Calling a virtual function involves dereferencing the virtual function table pointer, stored within the object. It is dereferencing the place in memory where this value is supposed to be, but of course, it's uninitialized garbage, hence the error.

From the context of the question, it looks to me like you might be interested in Placement new. Placement new will allow you to re-use heap memory that has already been allocated, but will properly initialize the vtable pointer.

Community
  • 1
  • 1
VoidStar
  • 5,241
  • 1
  • 31
  • 45
3

When a class declares one or more virtual functions, the compiler implicitly adds a V-Table pointer to the class declaration, and thereby, to each object.

For every virtual-function-call, the compiler generates code which reads the function's address from the object's V-Table pointer, and then jumps to that address.

The V-Table pointer of an object is initialized only during runtime, when the constructor of the class is called and the object is created.

So when you create an object without explicitly calling the object's class-constructor, the V-Table pointer of that object is not initialized.

Then, when you call a virtual function of that object, the CPU attempts to read the function's address from the object's V-Table pointer, and a memory access violation occurs.

barak manos
  • 29,648
  • 10
  • 62
  • 114
1

If you don't call the constructor of the object, then the virtual method table is not initialized. Therefore you can't expect calling a virtual function call to work. What are you trying to do in the first place >

hivert
  • 10,579
  • 3
  • 31
  • 56
1

Casting from an array of bytes into an object is only valid for POD types, that is, types that comply:

  • No user-defined destructor, constructor or copy operator.
  • Only public member variables.
  • No base classes.
  • No virtual functions.
  • No member variables of non-POD type, recursively.

That is, your first example is a POD, but your second one is not.

So your cast is valid for the first but not for the second. In the second case you will need to call placement new to construct a proper A object:

char *bytes = new char[sizeof(A)];
A *a= new (bytes) A;

And then, it is your responsibility to call the destructor when you are finished with it:

a->~A();
rodrigo
  • 94,151
  • 12
  • 143
  • 190
  • If RTTI is enabled, even casting to a POD data type would be a bad idea (I think). Although it probably wouldn't actually crash until you tried to use typeid or something. Therefore, I anticipate potential long term maintenance issues/accidents. I don't see why you wouldn't just always use placement new for the scenario. – VoidStar Mar 09 '14 at 10:06
  • It should work for trivially copyable classes as well. – david.pfx Mar 09 '14 at 10:44
  • @VoidStar: RTTI will not be affected by the cast. References to POD types cannot have different static and dynamic types, as they cannot have subclasses, so it doesn't matter. Moreover, `dynamic_cast` will only work properly with class with virtual functions. – rodrigo Mar 09 '14 at 10:47
  • @david.pfx: Hmmm, not sure, a trivially copyable class is not necessarily trivially constructible. Just now, I don't know if this is a requirement for what the OP is trying to do. – rodrigo Mar 09 '14 at 10:54
  • @rodrigo: Yes, TC can be virtual, so no good. How about standard layout? – david.pfx Mar 09 '14 at 13:15
  • @david.pfx: Standard layout can have non-trivial constructors and destructor, so you are probably not safe here. What you are probably looking for is a _trivial type_, that is a type that is trivially everything (copyable, constructible, destructible). Then, I think you may be right. – rodrigo Mar 09 '14 at 14:43
0

What are you expecting? Writing silly code results in silly results.

Anyway the objects need a virtual table - see What are you expecting? Writing silly code results in silly results. This table is not being initialised in the code supplied

See http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/

Ed Heal
  • 59,252
  • 17
  • 87
  • 127