-1

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.

Robin Green
  • 32,079
  • 16
  • 104
  • 187
Alok
  • 127
  • 1
  • 7
  • `A()` creates a temporary object which dies immediately. Using the pointer that pointed to it afterwards is undefined. – Quentin May 26 '18 at 11:02
  • what is the question exactly? have you answered it in the conclusions? – Mixone May 26 '18 at 11:18

1 Answers1

1

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
Swift - Friday Pie
  • 12,777
  • 2
  • 19
  • 42
  • 1
    "C++ allows to bind temporary only to const reference" -- and rvalue references. Nice answer nonetheless. – Quentin May 26 '18 at 11:41
  • @Quentin yeah, binding it to rvalue ref and returning as a reference would work. I meant it as workaround, as opposed to common newbie attempt to bind with non-const ^.^ – Swift - Friday Pie May 26 '18 at 11:48