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 ?
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.
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.
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 >
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();
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/
Related
When a class is instantiated, a virtual table pointer is created to point to its virtual table. And each virtual function is assigned a function address.
Will the pure virtual function be assigned a default function address?
class base {
public:
virtual void func() = 0;
};
class derived : public base {
public:
virtual void func() {
cout << "derived func" << endl;
}
};
int main()
{
base *ptr = new derived();
delete ptr;
ptr->func();
return 0;
}
I have run the demo on VS2017 and the error "performed a bad memory access" happened.
I know that the "__cxa_pure_virtual" will be called under the Linux system. So how do I implement my "__cxa_pure_virtual"? And how can I assign the function address to my pure function?
Calling a method in a deleted object is undefined behaviour, so in principle anything can happen and it’s your fault, but we can explain why you saw this behaviour.
First when you have a pure virtual function, the compiler could store a null pointer into the vtable, and when you call the function it crashes. Your compiler is helpful, it stores a pointer to a function named __cxa_pure_virtual, which is designed to crash when you call it. So a crash in this function tells you the crash was due to calling a pure virtual function. This is both more convenient for debugging, and it is safer to have a defined crash.
Second you deleted ptr. Deleting a derived object runs the derived class destructor, then it turns the object into a base class object, then it calls the base class destructor. Ptr had a pointer for a real func() in its vtable, but the csecond of these three steps replaced it with a pointer to __cxa_pure_virtual. It seems the memory for the object was released but not overwritten so your code manages to call the pure virtual function.
And you absolutely one hundred percent cannot implement __cxa_pure_virtual. It is already implemented. It crashes when called and that is intentional and how it should be.
Following a pointer to a deleted object is undefined behaviour.
Sometimes it will work, sometimes it will crash, sometimes it will format your hard drive.
In a typical implementation in machine code, deleted objects have their memory marked be recycled, This marking may or may not modify the data inside where the object was. At some poimt, another allocation will reuse that memory.
The vtable pointer is stored near the front of the object, and can be overwritten at any point. Or maybe not overwritten. Maybe it gets a pointer to a different vtable, which has a delete directory function there. Or maybe thr compiler does whole program optimization and proves every valid pointer to base is a pointer to derived, and devirtualizes every call.
I've got this trivial class hierarchy:
class Base {
public:
virtual int x( ) const = 0;
};
class Derived : public Base {
int _x;
public:
Derived( int x ) : _x(x) { }
int x( ) const { return _x; }
};
If I use malloc to allocate an instance of Derived, and then try to access the polymorphic function x, program crashes (I get a segmentation fault):
int main( ) {
Derived *d;
d = (Derived*) malloc( sizeof(Derived) );
*d = Derived( 123 );
std::cout << d->x() << std::endl; // crash
return 0;
}
Of course my actual application is a lot more complex (it's a sort of memory pool).
I'm pretty sure it's because of the way I allocate d: I didn't use new.
I know of placement new operator, which must be what I need, but I've never used it and have got some questions:
why is my application crashing, if I don't use new?
What does new actually do?
Why can't I just use the assignment operator to assign the value of Derived( 123 ); to the memory area pointed by d?
Would I need to use new also for non-polymorphic types?
How about POD ones?
On the C++Faq I linked above it says that the memory region passed to placement new must be aligned for the object I'm creating.
I know what alignment is, but I don't know how to check the alignment needed for my class.
malloc manual says:
The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable.
And I hope that the alignment needed for my class is the class size as returned by sizeof, so that any address in the form address_returned_by_malloc + i * sizeof(my_class) is suitable to allocate my objects.
Are my hopes right?
Let's go down the line
why is my application crashing, if I don't use new?
Virtual table is corrupted.
The virtual table is stuck right after the allocated memory. when you new a class, the generated code will properly set up the vtable. However, malloc will not properly initialize the vtable
To see the virtual table, run
g++ -fdump-class-hierarchy
Vtable for Derived
Derived::_ZTV7Derived: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived)
16 Derived::x
Class Derived
size=16 align=8
base size=12 base align=8
Derived (0x10209fc40) 0
vptr=((& Derived::_ZTV7Derived) + 16u) <-- notice how this is part of the structure
Base (0x10209fcb0) 0 nearly-empty
primary-for Derived (0x10209fc40)
For a similar reason, without overloading operator=, the generated assembly code will only copy the data and not the vtable [again, the compiler only knows to copy the data, not the vtable]
If you want to see a pointer-based version with a valid vtable function:
Derived e(123);
d = &e;
Would I need to use new also for non-polymorphic types?
If you are using virtual functions, then yes, even for non-polymorphic types
I hope that the alignment needed for my class is the class size as returned by sizeof, so that any address in the form address_returned_by_malloc + i * sizeof(my_class) is suitable to allocate my objects.
Alignment is not an issue.
Because malloc doesn't call the class's constructor, and doesn't know anything about any particular alignment requirements it might have. If you need to use malloc (not recommended), take a look at placement new (assuming you don't want to overload the regular new for some reason).
Classes with virtual members contain a pointer to a so-called vtable - basically a table of function pointers to the implementation of these virtual members. When you use operator new, the constructor is called, which, even if it is an implicit constructor, will set up this pointer to the vtable properly.
However, malloc does not call the constructor. The vtable pointer is left uninitialized, point to some random memory. When you then attempt to call a virtual function, you dereference a bad pointer and crash (undefined behavior).
The solution is to use placement new to initialize the object before using it:
int main( ) {
Derived *d;
d = (Derived*) malloc( sizeof(Derived) );
new(d) Derived(123); // invoke constructor
// You could also do:
// new(d) Derived;
// *d = Derived( 123 );
std::cout << d->x() << std::endl; // crash
// Although in your case it does not matter, it's good to clean up after yourself by
// calling the destructor
d->~Derived();
return 0;
}
Some important things to note:
Alignment is not a problem. Memory from malloc is properly aligned for any C++ type.
Assigning with = does not help. The default implementation of = copies all member variables, but the vtable pointer is not a member and is not copied.
Construction is not required for POD types. Non-POD types may or may not require it (it's undefined behavior if you don't). In particular, the constructor also calls member variable constructors; so if you don't construct the outer object, inner objects may be broken as well.
I don't belive that the object's constructor is called when you use malloc.
section [basic.life] of the standard says
The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ Note: initialization by a trivial copy/move constructor is non-trivial initialization. — end note ] The lifetime of an object of type T begins when:
storage with the proper alignment and size for type T is obtained, and
if the object has non-trivial initialization, its initialization is complete.
Since your class has virtual members, it requires non-trivial initialization. You can't assign an object whose lifetime hasn't started, you have to initialize it with new.
For the following code
class A
{
public:
~A()
{
std::cout << "a" << std::endl;
}
};
class B : public A {
public:
virtual ~B()
{
std::cout << "b" << std::endl;
}
};
int main()
{
B* b = new B();
A* a = b;
if (a == b)
{
}
delete a;
}
Question is , will “a” equals to “b” ? Why and How this happened?
And what a pointer really means? Not just an address and the length of the memory block?
will “a” equals to “b” ?
Yes
Why and How this happened?
To perform the comparison of the two pointers the compiler will perform a conversion to a common type. In this case, as A is a base of B, the conversion is to A*, yielding code equivalent to:
A* __tmp = b;
if ( a == __tmp ) ...
And what a pointer really means? Not just an address and the length of the memory block?
A pointer is a variable the holds the address of an object (no size information stored in the pointer). But the pointer has a type, and the compiler will interpret the memory location that the pointer refers to be an object of that type. That extra information that is stored outside of the pointer is what allows the compiler to perform the conversion.
The a variable will point at the A class portion of the allocated b object. A pointer is just a memory address, nothing more. What is important is what kind of data the pointer is pointing at in memory.
Let's split the answer in three parts
Pointers
A pointer is a variable which holds the memory address of another variable. The type of the pointed variable is important and will be checked by the compiler. One can force the pointer mechanic by using pointers to void (should be avoided in C++, unless you really know what you are doing).
Accessing derived class objects using base class pointers
An object, i.e. a variable, of a derived class (b in your code) can be referred to using a pointer to its parent type (A in your code). This will allow you to access the members of A that are present in B. As already stated by Richard J. Ross, using a pointer to the base class will yield the same address as using the derived class pointer (unless multiple inheritance is involved).
Virtual functions
Virtual methods allow you to call an overloaded method of the derived object using a base class pointer. This is especially useful for destructors because one can rest assured that objects will be properly destroyed even when using a base class pointer (assuming the destructor is well written).
Still, your code is conceptually wrong. Because the destructor of A is not virtual, the destructor of the B part of b will not be called, hence there might be memory leaks and similar problems.
As David already mentioned, simple comparison of two pointers a == b will give you True because the compiler will cast both of them to the common type.
But, if you were to modify this to (void*)a == (void*)b, result may be false.
This is because classes A and B have different memory layouts due to B having a virtual function table and A - not.
MSVC compiler puts virtual function pointer on the "top" of the class, before the first data member, but nothing stops other compilers from placing it on the "bottom".
You may also try making class A destructor virtual.
I found some explain on inside c++ object model, this is just like multiple inheritance, the vptr locates at the beginning of the object.
when the base class having no virtual and child class having a virtual, the assign of pointer will be adjusted by the compiler by step over the vptr,
The example is a comparison between two pointers. As they are pointing to the same location, a will be equal to b.
I've got this trivial class hierarchy:
class Base {
public:
virtual int x( ) const = 0;
};
class Derived : public Base {
int _x;
public:
Derived( int x ) : _x(x) { }
int x( ) const { return _x; }
};
If I use malloc to allocate an instance of Derived, and then try to access the polymorphic function x, program crashes (I get a segmentation fault):
int main( ) {
Derived *d;
d = (Derived*) malloc( sizeof(Derived) );
*d = Derived( 123 );
std::cout << d->x() << std::endl; // crash
return 0;
}
Of course my actual application is a lot more complex (it's a sort of memory pool).
I'm pretty sure it's because of the way I allocate d: I didn't use new.
I know of placement new operator, which must be what I need, but I've never used it and have got some questions:
why is my application crashing, if I don't use new?
What does new actually do?
Why can't I just use the assignment operator to assign the value of Derived( 123 ); to the memory area pointed by d?
Would I need to use new also for non-polymorphic types?
How about POD ones?
On the C++Faq I linked above it says that the memory region passed to placement new must be aligned for the object I'm creating.
I know what alignment is, but I don't know how to check the alignment needed for my class.
malloc manual says:
The malloc() and calloc() functions return a pointer to the allocated memory that is suitably aligned for any kind of variable.
And I hope that the alignment needed for my class is the class size as returned by sizeof, so that any address in the form address_returned_by_malloc + i * sizeof(my_class) is suitable to allocate my objects.
Are my hopes right?
Let's go down the line
why is my application crashing, if I don't use new?
Virtual table is corrupted.
The virtual table is stuck right after the allocated memory. when you new a class, the generated code will properly set up the vtable. However, malloc will not properly initialize the vtable
To see the virtual table, run
g++ -fdump-class-hierarchy
Vtable for Derived
Derived::_ZTV7Derived: 3u entries
0 (int (*)(...))0
8 (int (*)(...))(& _ZTI7Derived)
16 Derived::x
Class Derived
size=16 align=8
base size=12 base align=8
Derived (0x10209fc40) 0
vptr=((& Derived::_ZTV7Derived) + 16u) <-- notice how this is part of the structure
Base (0x10209fcb0) 0 nearly-empty
primary-for Derived (0x10209fc40)
For a similar reason, without overloading operator=, the generated assembly code will only copy the data and not the vtable [again, the compiler only knows to copy the data, not the vtable]
If you want to see a pointer-based version with a valid vtable function:
Derived e(123);
d = &e;
Would I need to use new also for non-polymorphic types?
If you are using virtual functions, then yes, even for non-polymorphic types
I hope that the alignment needed for my class is the class size as returned by sizeof, so that any address in the form address_returned_by_malloc + i * sizeof(my_class) is suitable to allocate my objects.
Alignment is not an issue.
Because malloc doesn't call the class's constructor, and doesn't know anything about any particular alignment requirements it might have. If you need to use malloc (not recommended), take a look at placement new (assuming you don't want to overload the regular new for some reason).
Classes with virtual members contain a pointer to a so-called vtable - basically a table of function pointers to the implementation of these virtual members. When you use operator new, the constructor is called, which, even if it is an implicit constructor, will set up this pointer to the vtable properly.
However, malloc does not call the constructor. The vtable pointer is left uninitialized, point to some random memory. When you then attempt to call a virtual function, you dereference a bad pointer and crash (undefined behavior).
The solution is to use placement new to initialize the object before using it:
int main( ) {
Derived *d;
d = (Derived*) malloc( sizeof(Derived) );
new(d) Derived(123); // invoke constructor
// You could also do:
// new(d) Derived;
// *d = Derived( 123 );
std::cout << d->x() << std::endl; // crash
// Although in your case it does not matter, it's good to clean up after yourself by
// calling the destructor
d->~Derived();
return 0;
}
Some important things to note:
Alignment is not a problem. Memory from malloc is properly aligned for any C++ type.
Assigning with = does not help. The default implementation of = copies all member variables, but the vtable pointer is not a member and is not copied.
Construction is not required for POD types. Non-POD types may or may not require it (it's undefined behavior if you don't). In particular, the constructor also calls member variable constructors; so if you don't construct the outer object, inner objects may be broken as well.
I don't belive that the object's constructor is called when you use malloc.
section [basic.life] of the standard says
The lifetime of an object is a runtime property of the object. An object is said to have non-trivial initialization if it is of a class or aggregate type and it or one of its members is initialized by a constructor other than a trivial default constructor. [ Note: initialization by a trivial copy/move constructor is non-trivial initialization. — end note ] The lifetime of an object of type T begins when:
storage with the proper alignment and size for type T is obtained, and
if the object has non-trivial initialization, its initialization is complete.
Since your class has virtual members, it requires non-trivial initialization. You can't assign an object whose lifetime hasn't started, you have to initialize it with new.
Hi I have a question about this pointer, when an object is constructed, when it is initialized? Which means, when can I use it? The virtual table is constructed in the constructor, is the same with this pointer?
For example, I have a code like this. The output is 8. Does it mean that before the constructor is entered, this pointer is already initialized?
class A{
public:
A() { cout<<sizeof(*this);}
int i;
int *p;
};
int main() {
A a;
}
If it is true, what else would happen before the constructor is entered ?
If it is not true, when is the this pointer initialized ?
The this pointer isn't a member of the object or class - it's an implicit parameter to the method that you call. As such it's passed in much like any other parameter - except that you don't directly ask for it.
In your example above, the constructor is a special method, which is in turn a special kind of function. When you construct the object, the compiler allocates memory for it (in this case on the stack, as a is a local variable in the main function. Then it automatically calls the constructor to initialise the object.
As part of calling the constructor, the implicit parameter this - a pointer to your object - is passed in as a parameter.
In a method with the following signature...
void MyMethod (const int* p) const;
there are actually two parameters, both pointers. There's the explicit parameter p and the implicit parameter this. The const at the end of the line specifies that this is a const pointer, much as the earlier one specifies that p is a const pointer. The need for that special syntax only exists because this is passed implicitly, so you can't specify const-ness in the normal way as with other parameters.
A "static" method doesn't have the implicit "this" parameter, and cannot directly access the object members either - there may not be a particular object associated with the call. It is basically a standard function rather than a method, except with access to private members (providing it can find an object to access).
As Steve Fallows points out, sizeof (this) is known at compile-time, because it is a pointer type and all pointers (*1) have the same sizeof value. The "8" you see implies you are compiling for a 64-bit platform. this is usable at this point - it points to valid memory, and all the members have completed their constructor calls. However, it isn't necessarily fully initialised - you are still in the constructor call after all.
EDIT
*1 - strictly, that may not be true - but the compiler knows what type of pointer it's dealing with here even though the value isn't known until runtime.
The this pointer is not stored. When the constructor is called for an object that occupies a specific memory location, that location is passed as a parameter to the constructor and other member functions.
If this would be stored inside the object, how to retrieve that pointer? Right, you would again need the this pointer :)
sizeof(*this) is known at compile time. So the cout statement reveals nothing about the initialization of this.
Given that the constructor can immediately begin accessing members of the object, clearly this is initialized before the constructor begins.
What else happens before the constructor? Well could be anything. I don't think the standard limits what a compiler could do. Maybe you should specify anything you're thinking might happen.
The virtual table is constructed in the constructor, is the same with this pointer?
The virtual table is NOT constructed in the constructor.
Typically, a single global v-table is shared by all instances of the same class, and each individual class has its own global v-table.The v-table is known at compile-time, and "constructed" at program load time.
The this pointer is "constructed" (I think "allocated" is a better term) at allocation time, that is, after the global new operator is called, and before the constructor is entered.
In cases where the object is stack-allocated instead of heap-allocated, global new is not called, but this is still available as a result of allocating stack-space, which is just before the constructor is entered.
The instance vptr is assigned after the object's memory is allocated, and just before the constructor is called.
Does it mean that before the constructor is entered, the this pointer is already initialized?
Yes, the value of the this pointer is known before the constructor is even called. This value is available via the this keyword inside constructors, constructor initialization lists, destructors, member methods. The this keyword behaves on the surface as a method variable (of pointer type) but is not one; it typically sits in a register (ecx on x86 platforms) and you typically won't be able to compile code like &this.
What else would happen before the constructor is entered
At least as far as the this pointer is concerned, the first thing that happens (unless using placement new) is the allocation of memory ultimately pointed to by this, be it on the stack (like in your example) or on the heap (using new.) At this point the this pointer is known. Then, either default constructors or explicitly specified constructors (via constructor initialization lists) are then called on the base classes (if any) and on your class non-POD member variables (if any). The class vtable pointer is also set before this point if your class contains virtual methods or destructor. Then, your class constructor body, if any, is invoked. (Constructor are called recursively, i.e. when a base class' constructor is called, the latter's base class constructors are called followed by non-POD member constructors, with the base class' vtable pointer being set, followed by the class' constructor body.)
The this pointer is the first argument to every call of the class, including the constructor.
When a class method is called, the address of the class is pushed onto the stack last (assuming cdecl calling convention here). This is read back into a register to use as the this pointer.
Constructors are in fact called as if they were ordinary member functions.
You cannot have a virtual constructor because the constructor is responsible for setting the vtable member.
As nobugz already pointed out, your example doesn't really mean much -- sizeof yields its results based on the type of the object you pass to it. It does not evaluate its operand at run-time.
That said, yes, this is initialized before entry to the ctor. Basically, the compiler allocates space for the object (on the stack if the object has automatic storage duration, or using ::operator new if it has dynamic storage duration). Upon entry to the ctor, the ctors for base classes (if any) have already run to completion. When your ctor is called, this gives the address of the memory that was allocated for the object.
this starts pointing to the current object and all members and base classes have been initialized before you enter the constructor body.
Therefore, you can hand out pointer to this in the initialization list, but the receiver should do nothing else other than storing it, because the pointed-at instance may not be fully constructed at the time.
#include <iostream>
class B;
class A
{
B* b_ptr;
public:
A(B* b);
};
class B
{
A a;
int i;
public:
B(): a(this), i(10) {}
void foo() const { std::cout << "My value is " << i << '\n'; }
};
A::A(B* b):
b_ptr(b) //Ok to store
{
b_ptr->foo(); //not OK to use, will access initialized member
}
int main()
{
B b;
}