function call via class pointer in c++ - c++

#include"iostream"
using namespace std;
class base{
public:
void f()
{
cout<<"base f:"<<endl; // prints base f:
}
};
int main()
{
base *b; // even same out put with " base *b =NULL; "
b->f();
return 0;
}
O/p : base f:
can any one please explain how the function is getting called without assigning the object to the pointer .
Thanks.

Call of member-function with not initialized (or initialized to 0) pointer to object is undefined behaviour, however it may works since there is no attempts to access variables of object and there is no vtable here. You can look at this function like
void f_base(base* p)
{
cout << "base f:" << endl;
}
there is no access - there is no error, on all modern-compilers it will work, but it can be changed anytime.

This is invalid code, but since nothing in base::f() accesses a member variable, no invalid memory is getting touched.
If you add a member and try to print it out in the function, you will almost undoubtedly get a crash.

You need to use new
i.e.
base *b; // even same out put with " base *b =NULL; "
should be
base *b = new base;
... Need a delete to prevent memory leaks

Related

Why does this static C++ cast work?

Imagine this code:
class Base {
public:
virtual void foo(){}
};
class Derived: public Base {
public:
int i;
void foo() override {}
void do_derived() {
std::cout << i;
}
};
int main(){
Base *ptr = new Base;
Derived * static_ptr = static_cast<Derived*>(ptr);
static_ptr->i = 10; // Why does this work?
static_ptr->foo(); // Why does this work?
return 0;
}
Why do I get the result 10 on the console? I wonder because I thought the ptr is a pointer to a base object. Therefore the object doesn't contain a int i or the method do_derived(). Is a new derived-Object automatically generated?
When I declare a virtual do_derived() method in the Base class too, then this one is chosen, but why?
int* i = new int{1};
delete i;
std::cout << *i << std::endl;
This will also "work", if the definition of working is that the code will compile and execute.
However, it is clearly undefined behavior and there are no guarantees as to what might happen.
In your case, the code compiles as static_cast won't perform any checks, it just converts the pointer. It is still undefined behavior to access memory that hasn't been allocated and initialized though.
As mentioned in the comments, "happens to do what you expected" is not the same as "works".
Let's make a few modifications:
#include <iostream>
#include <string>
class Base{
public:
virtual void foo(){
std::cout << "Base::foo" << std::endl;
}
};
class Derived: public Base{
public:
int a_chunk_of_other_stuff[1000000] = { 0 };
std::string s = "a very long string so that we can be sure we have defeated SSO and allocated some memory";
void foo() override {
std::cout << "Derived::foo" << std::endl;
}
void do_derived() {
std::cout << s << std::endl;
}
};
int main(){
Base *ptr = new Base;
Derived * static_ptr = static_cast<Derived*>(ptr);
static_ptr -> foo(); // does it though?
static_ptr -> do_derived(); // doesn't work?
static_ptr->a_chunk_of_other_stuff[500000] = 10; // BOOM!
return 0;
}
Sample Output:
Base::foo
Process finished with exit code 11
In this case, none of the operations did what we expected. The assignment into the array caused a segfault.
The statement:
Base *ptr = new Base;
Doesn't always allocate sizeof(Base) - it would probably allocate more memory. Even if it does allocate exact sizeof(Base) bytes, it doesn't necessarily mean any byte access after this range (i.e. sizeof(Base)+n, n>1) would be invalid.
Hence let's assume the size of class Base is 4 bytes (due to virtual function table in most compiler's implementation, on a 32-bit platform). However, the new operator, the heap-management API, the memory management of OS, and/or the hardware does allocate 16 bytes for this allocation (assumption). This makes additional 12 bytes valid! It makes the following statement valid:
static_ptr->i = 10;
Since now it tries to write 4 bytes (sizeof(int), normally) after the first 4 bytes (size of polymorphic class Base).
The function call:
static_ptr->foo();
would simply make a call to Derived::foo since the pointer is of type Derived, and nothing is wrong in it. The compiler must call Derived::foo. The method Derived::foo doesn't even try to access any data member of derived class (and even base class).
Had you called:
static_ptr->do_derived();
which is accessing i member of derived. It would still be valid, since:
The function call is always valid, till method tries to access data-member (i.e. accesses something out of this pointer).
Data-member access became valid due to memory allocation (UD
behaviour)
Note that following is perfectly valid:
class Abc
{
public:
void foo() { cout << "Safe"; }
};
int main()
{
Abc* p = NULL;
p->foo(); // Safe
}
The call it valid, since it translates to:
foo(NULL);
where foo is:
void foo(Abc* p)
{
// doesn't read anything out of pointer!
}
why does this static cast work?
Because static cast is compile time checker. There is a relationship between Base and Derived. Since it has relationship, static cast believe's that relationship and believe's the programmer too. So As a programmer, you should make sure that Base object should not be static casted to derived class object.

facing error for calling member function with pointer

As i have read that if we create object through pointer, it wont delete automatically. but when i am calling member function with pointer its giving error
#include <iostream>
using namespace std;
class Base
{
protected:
int i;
public:
Base(){}
Base(int a) { i = a; }
virtual void display()
{ cout << "I am Base class object, i = " << i << endl; }
~Base(){
cout<<"tsp";
}
};
int main()
{
//Base b(33);
{
Base *u=new Base() ;
}
u->display();
//delete u;
return 0;
}
O/P:'u' was not declared in this scope but still the memory exist
The pointer is not being deleted, but u goes out of scope when the block it is declared in ends; u is only available within that block. Therefore, calling u->display() is an error because there is no u variable in scope anymore.
Note that because it's not automatically deleted (going out of scope is not the same thing as being deleted), you are leaking the memory allocated by the Base object.
To put it another way, u points to a Base object but it is not itself the object. The pointer can go away, but the object can still exist. It's like if I had someone's business card and threw it away. Their phone number or email address don't cease to exist just because I threw away my record of it.
"u goes out of scope" is throwing away the business card.
"delete u" is... disconnecting the phone line on the business card, I guess.
Contrast this with the following code, using a smart pointer:
int main() {
std::cout << "top\n";
{
std::unique_ptr<Base> u{new Base()};
}
std::cout << "bottom\n";
}
In this case, when u goes out of scope, the smart pointer will be destructed and the Base allocation will be freed (you will see the output tsp before you see the output bottom).

Deleting polymorphic objects and memory leaks

Suppose I have a class A and a class B which inherits from A.
Then I do something like:
A* a = new B();
delete a;
Why a memory leak happens only when there is a dynamic memory allocation within B?
How C++ knows to remove the "B part" when there is dynamic memory allocations within B but fails where it is?
[Update:]
How does the following code does not result in a memory leak: [I suspect it to be undefined behaviour, but I don't really understand anything :(]
#include <iostream>
using std::cout;
using std::endl;
class A {
public:
virtual void f() {
cout << "1" << endl;
}
~A() {
cout<< "A A'tor" << endl;
}
};
class B : public A {
private:
public:
B(){}
~B(){
cout<< "B D'tor" << endl;
}
void f() {
cout << "2" << endl;
}
};
int main() {
A* a = new B();
//a->f();
delete a;
return 0;
}
While compiler sees statement "delete a;"
It knows only static type of "a" is pointer to A, if there is no virtual destructor in class A. As a result wrong destructor gets called leading to memory leak
If there is a virtual destructor in class A
then compiler comes to know that Dynamic type of "a" is pointer to B and there will a vtable from where it will get B's destructor address at run time
This is because the destructor isn't virtual. If there is ever a chance in your program to delete derived class objects via base class pointers, you should define a virtual destructor in the base class. This will allow B's destructor to get called first, allowing you to free any dynamic memory B may have allocated. A's destructor will get called after B's.
Another good rule of thumb is to train yourself to think about making your destructor virtual anytime you make a method virtual. Since the motivation to make a method virtual means you will be calling methods on base class pointers, it follows that you will likely be deleting objects through base class pointers.

dynamic cast to non-derived object in order to call a function works?

I read in a C++ book that you can use dynamic_cast to downcast a pointer to a base object to a derived object pointer, if the object it points to actually is that of the derived type. The format is dynamic_cast<Derived*>(basePointer). Furthermore, I read on this website that dynamic_cast should return a null pointer if the object it points to cannot be converted to the derived class type.
However, I recently tried having a pointer to a plain object with a virtual function downcast to an object that's derived from a different class, in order to call one of that class' functions. To my surprise, it worked:
#include <iostream>
using namespace std;
class Object {
public:
virtual ~Object () {}
};
class Base {
public:
virtual void doSomething () {
cout << "Done something!" << endl;
}
};
class Derived: public Base {
public:
virtual void doSomething () {
cout << "You done goofed!" << endl;
}
void printFoo () {
cout << "Foo" << endl;
}
private:
int x;
};
int main () {
Object o;
Object* p = &o;
if(dynamic_cast<Derived*>(p))
cout << "Yep, baby is derived!" << endl;
else
cout << "Isn't derived." << endl;
dynamic_cast<Derived*>(p)->printFoo();
return 0;
}
Here, Base is a base class type designed to be used polymorphically (that is, it contains a virtual function), and Derived is a class type derived from Base. Object is just a plain class that is not related to either class, but its destructor is made virtual so that it can be used polymorphically. I'll explain the purpose of Derived::x in a moment. In the main function, an Object is created and a pointer to Object is assigned to its address. It checks whether Derived is a descendant of that pointer, and prints whether it is or it isn't. Then it casts that pointer to a pointer of type Derived, and Derived's printFoo function is called.
This shouldn't work, but it does. When I run it, it displays "Isn't derived," so it clearly understands that Obect is not Derived from Base, but then it prints "Foo" on the screen and exits without error. However, if I add the line x = 1; to the printFoo function, it exits with a Segmentation fault, as it's trying to assign a variable which doesn't exist in that object. Furthermore, this only seems to work with non-virtual functions. If I try to call the virtual function doSomething, for instance, I get the Segmentation fault before "You done goofed!" is ever printed out.
What's going on here? Shouldn't dynamic_cast<Derived*>(p) return a null pointer, so that trying to call printFoo from that would automatically cause an error? Why is that working when it shouldn't?
You've already established that dynamic_cast is returning a NULL pointer, so the real question is why function calls on a NULL object pointer appear to work in some cases but not others.
In ALL of these cases you're getting undefined behavior. Just remember that undefined doesn't always mean crash - sometimes you get perfectly reasonable results. You just can't rely on it.
Here's an explanation based on what's probably going on, but there are no guarantees it will work the same way tomorrow, much less when you change the optimization settings or get a new version of the compiler.
printFoo isn't virtual, so there's no need to use a vtable to access it. doSomething is virtual so it does need the vtable. A NULL pointer doesn't have a vtable so calling doSomething blows up immediately.
printFoo doesn't use any of the members of the object until you add the x = 1 line to it. As long as the compiler doesn't generate any code that accesses the this pointer, it's likely to work fine.
It works because
dynamic_cast<Derived*>(p)->printFoo();
returns a null pointer as expected, but the null pointer is of type Derived. When it calls printFoo, it works because printFoo does not use any member variable, in which case it would refer to this for using that variable, and would crash for dereferencing null pointer. Since no member variable is used, no reference to this, no problem( that's why it gives segfault when u use x in the method).
It is same as following simple code:
class A{
public:
int x;
void f1(){}
void f2(){x=1;}
}
A* x=nulptr;
x->f1(); // will work
x->f2(); // UB
You're accessing a null pointer without using any actual object state, which is safe though meaningless.
If you change Derived::printFoo() to the following, you'll actually be in "undefined behavior territory", and will very likely segfault:
void printFoo () {
cout << "Foo: " << x << endl;
}
For what it's worth, using references instead of pointers will make this throw an exception if you'd rather propagate the failure outward than test and deal with it locally:
dynamic_cast<Derived &>(*p).printFoo(); // kaboom! throws std::bad_cast

C++ Debug Assertion Fails Only With VPTR

I'm wondering why I get an exception on the delete part in one case here, but not in the other.
No exception case
#include <iostream>
using namespace std;
class A
{
public:
~A() { cout << "A dtor" << endl; }
};
class B : public A
{
public:
int x;
~B() { cout << "B dtor" << endl; }
};
A* f() { return new B; }
int _tmain(int argc, _TCHAR* argv[])
{
cout << sizeof(B) << " " << sizeof(A) << endl;
A* bptr= f();
delete bptr;
}
Herethe output is 4 1 .. A dtor, since A has 1 byte for identity and B has 4 because of int x.
Exception case
#include <iostream>
using namespace std;
class A
{
public:
~A() { cout << "A dtor" << endl; }
};
class B : public A
{
public:
virtual ~B() { cout << "B dtor" << endl; }
};
A* f() { return new B; }
int _tmain(int argc, _TCHAR* argv[])
{
cout << sizeof(B) << " " << sizeof(A) << endl;
A* bptr= f();
delete bptr;
}
Here the output is 4 1 .. A dtor, since A has 1 byte for identity and B has 4 because of the vptr that's needed for its virtual destructor.
But then a debug assertion fails inside the delete call (_BLOCK_TYPE_IS_VALID).
Environment
I'm running Windows 7 with Visual Studio 2010 SP1Rel.
See this post
A quick summary:
You are telling the machine to delete an instance of A
As this is a class which we call through pointer/reference maybe we should use a virtual table (VT)?
There is no virtual members in A thus no VT is used
We call the standard destructor of A…
Bang! We are trying to delete class A but it happens that the pointer
has lead us to object of B which contains VT which A didn't know of.
sizeof(A) is 1 (as AFAIK it’s not legal to have size equal 0) and
sizeof(B) is 4 (due to presence of VT). We wish to delete 1 byte, but
there is a block of 4 bytes. Due to DEBUG heap monitoring, the error
was caught.
The solution of course is to declare the base class's (A's) dtor as virtual so B's dtor will always be called.
EDIT: For the first case, here's what the standard has to say:
§5.3 In the first alternative (delete object), if the static type of the object to be deleted is different from its
dynamic type, the static type shall be a base class of the dynamic type of the object to be deleted and the
static type shall have a virtual destructor or the behavior is undefined. In the second alternative (delete
array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined.
So both cases lead us to the realm of undefined behavior which of course differs from one implementation to the other. But it stands to reason that for most implementations the first case is easier to handle or at least easier to contemplate than the second which is just an esoteric anti-pattern.
As others have pointed out, you are deleting an object whose static type is different from its dynamic type, and since the static type doesn't have a virtual destructor, you get undefined behavior. This includes the behavior of sometimes working and sometimes not working as you are seeing. However, I think you are interested in a little deeper understanding of what is happening with your particular compiler.
Class A has no members at all, so its data layout ends up looking like this:
struct A {
};
Since class B derives from class A, class A becomes embedded within B. When class B has no virtual functions, the layout ends up looking like this:
struct B {
A __a_part;
int x;
};
The compiler can convert a B* to an A* by just taking the address of __a_part, as if the compiler had a function like this:
A* convertToAPointer(B* bp) { return &bp->__a_part; }
Since __a_part is the first member of B, the B* and the A* point to the same address.
Code like this:
A* bptr = new B;
delete bptr;
Is effectively doing something like this:
// Allocate a new B
void* vp1 = allocateMemory(sizeof(B));
B* bp = static_cast<B*>(vp1);
bp->B(); // assume for a second that this was a legal way to construct
// Convert the B* to an A*
A* bptr = &bp->__a_part;
// Deallocate the A*
void* vp2 = ap;
deallocateMemory(vp2);
In this case, vp2 and vp1 are the same. The system is allocating and deallocating the same memory address, so the program runs without an error.
When class B has a virtual member function (the destructor in this case). The compiler adds a virtual table pointer, so class B ends up looking like this:
struct B {
B_vtable* __vptr;
A __a_part;
};
The issue here is that __a_part is no longer the first member, and the convertToAPointer operation will now change the address of the pointer, so vp2 and vp1 no longer point to the same address. Since a different memory location is being deallocated than the one that was allocated, you get the error.