I have three classes: Base, Derived (inherits from Base), and Stats (which uses a Base).
The program makes a Derived object, which may be deleted and reconstructed several times during the program's execution. It also sets up a Stats object which will only be created once, but needs to call functions on the Base of the Derived object. Because the Derived object may be reconstructed, the Stats object will need a reference to a pointer of Base, since the value of the pointer may change. However, when I construct a new Derived in main, the reference in the Stats class doesn't see the new object.
In the example below, d and m_obj both are null, then when I make a new Derived instance, m_obj still is null. This doesn't make sense to me. What confuses even more, is if I change the line Derived* d = 0; to Base* d = 0;, it works fine. Any thoughts?
#include <iostream>
using namespace std;
class Base {
};
class Derived : public Base {
};
typedef Base* const base_ptr;
class Stats {
public:
Stats(Base * const &obj) : m_obj(obj) {
cout << "In Stats():" << endl;
cout << " m_obj = " << m_obj << endl;
}
void f() const {
cout << "In f:" << endl;
cout << " m_obj = " << m_obj << endl;
}
private:
base_ptr &m_obj;
};
int main() {
Derived* d = 0;
cout << "d = " << d << endl;
Stats s(d);
d = new Derived();
cout << "d (after new) = " << d << endl;
s.f();
return 0;
}
You are creating a reference to a temporary Base * that points to what d was pointing at (NULL in this case). That temporary is destroyed after line that invokes the constructor finishes executing. Congratulations, you've just invoked undefined behavior! After that, anything can happen.
Essentially, this line reads like this if you expand out what's really happening:
Stats s(d);
really:
{
Base * const tmp = d;
Stats s(tmp);
}
Except, of course, s doesn't go away like it would in this example.
When d is of type Base * then the compiler doesn't have to do any type conversion and so doesn't have to create any temporaries.
Your Stats gets actually a temporary copy of the value of d. This is because d is not of the type Base * const & (but can be converted to).
Related
Class B expects to receive an instance of shared_ptr<IError>.
Class A implements IError and is passed by value to the constructor of B.
I would like to understand how this scenario is handled. How does the shared_ptr as a template class handle the conversion to IError?
In a simple case where B receives shared_ptr<A> I assume the copy constructor is called and the reference counter is increased. However since IError is pure virtual a normal copy constructor invocation seems not to be case here?
// Example program
#include <iostream>
#include <string>
class IError
{
public:
virtual ~IError(){};
virtual void OnError() = 0;
};
class A : public IError
{
public:
A(){};
void OnError(){std::cout << "Error Occured" << std::endl;}
};
class B
{
public:
B(std::shared_ptr<IError> errorReporter): mErrorReporter(errorReporter){}
void Action(){mErrorReporter->OnError();}
private:
std::shared_ptr<IError> mErrorReporter;
};
int main()
{
auto objA = std::make_shared<A>();
auto objB = std::make_shared<B>(objA);
objB->Action();
}
Debugging time! Let's find out what happens by using the tools we have available as developers.
The memory of the shared_ptr objA looks like this (type &objA in the memory window; it will be replaced by its address):
It has a pointer to the object (000002172badd8e0) and a pointer to the control block.
The control block looks like this (copy and paste the second value into a new memory window):
It has a pointer to the allocator (first 2 columns), the reference count (1) and the weak reference count (0 + offset 1).
After objB has been created, the control block of objA has changed to a reference count of 2:
And the shared_ptr objB looks like this:
It points to the a shared pointer and to the control block.
The shared pointer in objB points to the same object as before (000002172badd8e0), so no copy of the actual object has been made.
The control block of objB indicates that objB only has a reference count of 1:
a normal copy constructor invocation seems not to be case here?
Correct. No copy of the object is made, as we can confirm with a debugger. But a copy of the shared_ptr has been made.
It doesn't.
Copy a shared_ptr doesn't copy it's point-to object, just like normal pointer
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<IError> i = a;
A* a = new A;
IError* i = a; // no copy A
You are right in that the base class IError is abstract, hence it cannot be instantiated, never mind copied.
The code below has been modified from the original to show how each newly created shared_ptr just increments the reference count of the original shared_ptr. So, a shallow copy.
In your code, as well as in the code below, the underlying object to these shared_ptrs is concrete class A, derived from the abstract IError, so it is legal to shallow copy it.
// Example program
#include <iostream>
#include <string>
#include <memory>
class IError
{
public:
virtual ~IError(){};
virtual void OnError() = 0;
};
class A : public IError
{
public:
A(){std::cout << "A created.\n";};
void OnError(){std::cout << "Error Occured" << std::endl;}
};
class B
{
public:
B(std::shared_ptr<IError> errorReporter): mErrorReporter(errorReporter){
std::cout << "B created from A.\n";
}
void Action(){mErrorReporter->OnError();}
private:
std::shared_ptr<IError> mErrorReporter;
};
int main()
{
auto objA = std::make_shared<A>();
std::cout << "I. Reference count for objA: " << objA.use_count() << '\n';
auto objB = std::make_shared<B>(objA);
std::cout << "II. Reference count for objA: " << objA.use_count() << '\n';
// objB->Action();
auto objBB = std::make_shared<B>(*objB);
std::cout << "Created objBB from objB\n";
std::cout << "III. Reference count for objA: " << objA.use_count() << '\n';
std::cout << "Reference count for objB: " << objB.use_count() << '\n';
std::cout << "Reference count for objBB: " << objBB.use_count() << '\n';
// auto objB_from_base = std::make_shared<B>(IError()); // ERROR: IError is an abstract class
}
with output:
A created.
I. Reference count for objA: 1
B created from A.
II. Reference count for objA: 2
Created objBB from objB
III. Reference count for objA: 3
Reference count for objB: 1
Reference count for objBB: 1
Take a look at this piece of code:
#include <iostream>
class A{
public:
int x;
virtual void f(){std::cout << "A f\n";}
};
class B: public A
{
public:
int y;
void f() {std::cout << "B f\n";}
};
void fun( A & arg)
{
std::cout << "fun A called" << std::endl;
arg.f();
// arg.y = 222; - this gives error, compiler's work?
arg.x = 2223333;
}
void fun(B & arg){
std::cout << "fun B called" << std::endl;
arg.f();
}
int main()
{
B b;
b.y = 12;
b.x = 32;
fun(static_cast<A&>(b));
std::cout << b.x << " " << b.y << std::endl;
return 0;
}
What exactly happens when I reference cast b into A&? I'm guessing a reference to type A 'arg' is created in a funtion 'fun()' and now it's only compiler's work to differentiate types? Meaning no actual object was created and no slicing occurred and it's still the same object in memory, however compiler will treat it as type A? (meaning after function call I can safely use b as type B?)
I assumed that's true, because the vptr of the instance didn't change (arg of type A called B's virtual function override), but I'm not completely sure what's going on behind the scenes during reference casting.
Also, if I assign static_cast<A&>(b) to a new object of type A, I assume that's when the construction of a new object of type A and slicing occurres?
Yes, you seem to have got this. :-)
A B is also an A (by inheritance), so it can bind to either A& or B&. Nothing else happens, it is just a reference to the existing object.
The slicing happens if you assign a B object to an A object, like A a = b;, which will only copy the inherited A portion of b.
I was trying to create an object inside static function using a constructor.
Here is the code
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; setAddr(this); }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static A* addr;
static void setAddr(A* ad) { addr = ad; }
static A &create() { A(); return *addr; }
};
A* A::addr = NULL;
int main() {
A &ptr = A::create();
std::cout << "a = " << ptr.a << std::endl;
ptr.a = 100;
std::cout << "a = " << ptr.a << std::endl;
getch();
return 0;
}
I know using new is best way to do it,but i was trying to do it using contructor to know whether it can be done or not.
The output was:
constructor called... 009AF874
destructor called... 009AF874
a = 10
a = 100
Now here is my question,
1) why destructor is called when did not create an object using any declaration like A obj;
2) and if the destructor is called then how I am able to assign a value to otr.a;
By looking at the program's output I made the following conclusion.
1) I read somewhere that constructor is called after the memory has been allocated to object. And if an object is created then it has to be destroyed and the scope of the obj decided to destroy it now.
2) Since object address has previous values before destroying it and returns call return the address of the variable storing it. When I try to access it, I was able to do so because that memory address still exists.
That's not how you make a singleton. The statement
A();
creates a temporal object of class A that is destroyed (as per standard) at end of statement.
Indeed, memory is allocated before call of constructor. Resulting object can be assigned or passed by reference or value to any function of this statement, but in former case, reference is valid only until end of call expression. Exception is that if it was assigned to reference, its length of life is extended to one
of reference. After life of object ended, any access to memory it used results in UB, provided that it could be used by any other operations.
Any access to object after destructor was called is an UB as well.
Here is an example (this code intentionally contains UB)
#include <iostream>
class A {
public:
A() { this->a = 50; std::cout << "constructor called... " << this << std::endl; }
~A() { this->a = 10; std::cout << "destructor called... " << this << std::endl; }
int a;
static const A &create() {
const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
};
int main() {
const A &ref = A::create();
std::cout << "a = " << ref.a << std::endl;
return 0;
}
Note, that C++ allows to bind temporary only to const reference. There are way to work around that, but that's irrelevant.
Output of this program may vary, depending on compiler and level of optimization. E.g. clang with no optimization:
constructor called... 0x7ffc1f7991d0
a = 50
destructor called... 0x7ffc1f7991d0
a = 4202884
gcc may output 10 in last line. MS may crash on it. Keyword is "may", there is no rule that governs what would happen. Object stopped existing after create() returned reference to it because lifespan of addr came to end, and we are left with dangling reference.
Obviously we can extend lifespan of addr by making it static.
static const A &create() {
static const A& addr = A();
std::cout << "a = " << addr.a << std::endl;
return addr;
}
Static variable in function's scope will be created at first call of function and stops to exist when process stops.
constructor called... 0x6031b8
a = 50
a = 50
destructor called... 0x6031b8
class A {
public:
A(void) { cout << "A::A" << endl; }
A(const A& a) { cout << "A::A(a)" << endl; }
virtual ~A(void) { cout << "A::~A" << endl; }
virtual void g(void) { cout << "A::g" << endl; }
};
class B : public A {
public:
B(void) { cout << "B::B" << endl; }
~B(void) { cout << "B::~B" << endl; }
void g(void){ cout << "B::g" << endl; }
};
void print(A c) {
cout << "print" << endl;
}
int main(void) {
A a;
B b;
A* c = &b;
c->g();
print(*c);
return 0;
}
I don't understand why this statement A::A(a) get's executed when calling c->g() or print(*c);
And I'm not quite sure to which part of the programm does the Method print belongs to?
Since you pass the argument by value to the print function, a copy must be made using the copy constructor. That is why your copy constructor is called when print is called.
If you change to call be reference (or by passing a pointer) then no copying will be made.
And as stated by others, print is a "normal" function, also known as a "free" function, or a non-member function. It "belongs" to the program, and exist in the global scope and have external linkage.
Print isn't a method, it's a function, as such it doesn't "belong" anywhere - it's simply part of your program.
Functions are from the age before Object-Orientation, though still have an important place.
The void print(A c) Function can be broken down as follows:
void, this is the return value, in this case - nothing.
print(, this is the name of the function.
A c), this means it will take a
single parameter of type A, named c.
As such A::A(const A &) is the copy constructor of the object A; Essentially this method will be called Every time an object of type A is copied into a new object of type A
When you call print(*c), you derefrence The pointer c, this results in a reference to the object pointed to by c (ie: an object of type A). This is then copy constructed into the print function, resulting in a temporary const A & that is used by the function.
This is why the Copy-constructor is called.
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.