HQW.ang
HQW.ang

Reputation: 163

Call global instance of a class object inside its constructor

It may sound weird as what the title says. Why not just use this to call any members than use a global instance of the class itself. But in a project, I just realized I do write such kinds of codes after I finished and reviewed them.

Here is a piece of prefabricated sample codes.

// header.h
#ifndef HEADER_H
#define HEADER_H

class Foo
{
public:
    Foo();

    void bar();
};

#endif /* HEADER_H */
// header.cpp
#include "header.h"
#include <iostream>

Foo foo;

Foo::Foo()
{
    foo.bar(); // <= notice here, rather than this->bar() or directly a bar().
}

void Foo::bar()
{
    std::cout << "Hello bar" << std::endl;
}
// main.cpp
#include "header.h"

extern Foo foo;

int main(int argc, char *argv[])
{
    foo.bar();
    return 0;
}
$ g++ -Wall -std=c++11 main.cpp header.cpp -o foo
$ ./foo
Hello bar
Hello bar

It compiled without any complains and ran well. But I wonder how can this happens. When the program sees a global instance of the class, it's supposed to call the constructor. But insides the constructor the instance is again invoked. Is this a paradox that an instance calls itself before the instance finishes construction process.

And another question, what is available before and after constructor? It seems all member variables and methods have prepared well and been available in advance.

Upvotes: 2

Views: 290

Answers (1)

Serge Ballesta
Serge Ballesta

Reputation: 148910

In fact, the standart (n4659 15.7 [class.cdtor] §3)explicitely allows that

member functions, including virtual functions (13.3), can be called during construction or destruction

Apparently, this code uses the object foo in its constructor before that object is fully constructed which should be UB. But as the shown code only uses that object, it will be the first Foo ever constructed. At the moment when its constructor is called, foo is this and calling bar on it is legal.

But if the application contains any other Foo object of static or thread storage duration in a different translation unit, or in the same translation unit but before foo, then the program will invoke UB:

Foo bar;             // initialization of bar invokes UB
extern Foo foo;

Upvotes: 1

Related Questions