0

Edit: Code compiling now. Also added more detailed code to depict exact scenario.

Is it safe to pass this pointer in the initializer list ? Are there any chances of segmentation fault in case object methods are called before object is constructed? Or better to pass this pointer in constructor ? following are the example classes.

#include "iostream"

using namespace std;

class Observer
{
public:
    Observer() = default;
    
protected:
    Observer(const Observer& other) = default;
    Observer(Observer&& other) = default;

    Observer& operator=(const Observer& other) = default;
    Observer& operator=(Observer&& other) = default;
    
public:
    virtual ~Observer() = default;
    
    virtual void method() const 
    {   
    }
};

class ThirdClass
{
public:
    ThirdClass(const Observer* const first) : firstPtr{first}
    {
        // register for some events here.
        
        // that events will call someMethod and someMethod is calling FirstClass's method, before initializer list of FirstClass gets executed.  
    }
    
    void someMethod()
    {
        firstPtr->method();
    }
    
    static ThirdClass& getInstance(const Observer* const first)
    {
        static ThirdClass instance = ThirdClass(first);
        return instance;
    }

private:
    const Observer* firstPtr{};
};

class FirstClass: public Observer
{
public:
    FirstClass():third(ThirdClass::getInstance(this))
    // init
    // init
    // some big initializer list which will take time to inilialize
    {      
    }
    
    virtual void method() const override
    {      
    }
    
private:
    const ThirdClass& third;
};

int main()
{
    FirstClass firstObj;
    return 0;
}

Assume the scenario like, Initializer list of FirstClass is very big and before its complete execution, event is fired(For which, third class is registered) and that event calls the someMethod() of ThirdClass. Does this will cause undefined behavior. Or there are not at all chances of Undefined Behaviour ?

PS: there is similar question here Is it safe to use the "this" pointer in an initialization list? But that mentions some parent child relationship.

Vishal
  • 516
  • 5
  • 9
  • 1
    Is the `first`, in `ThirdClass`'s constructor, used? Or is it just stored? If you are just storing the pointer, then this is safe and well defined. If you attempt to use the pointer in the constructor, then it would be undefined. – ChrisMM May 27 '22 at 11:51
  • 2
    For starters, it doesn't compile (even after you fix typos). – HolyBlackCat May 27 '22 at 11:54
  • Yes, they are used. Should I completely avoid calling Thridclass constructor in the iniliazer list ? – Vishal May 27 '22 at 11:54
  • If they are used in the constructor, then it is UB, since the `this` is not finished construction. It's memory address is valid, so it can be stored, but not used. – ChrisMM May 27 '22 at 11:57
  • 2
    This code is fundamentally broken. I recommend you make a [mcve], and paste that code from you editor to the question as-is. – hyde May 27 '22 at 12:04
  • Anyway, `third` is a reference, You should be initializing it to be a reference to a `ThirdClass` instance. You are now initializing it with `FirstClass*` pointer. Doesn't make sense. – hyde May 27 '22 at 12:05
  • **Yes**, it is safe to pass `this` in initializer list, but only to store for future use; it cannot be dereferenced (because the object hasn't been constructed yet). The code snippet provided is completely broken. – Eljay May 27 '22 at 12:16
  • If you use `class FirstClass : ThirdClass` then you don't need to pass `this` and `ThirdClass` can define some virtual methods that `FirstClass` then implements for the use of `ThirdClass`. Would that solve your problem? – Goswin von Brederlow May 27 '22 at 13:35
  • Please have a look, I have updated the code, which explains exact scenario, also it is compiling now. – Vishal May 28 '22 at 04:18

1 Answers1

0

If the first variable, in ThirdClass's constructor is not used, only stored for future use, then this is safe and well defined. If you attempt to use/dereference the pointer in the constructor, then it would be undefined behaviour, since the FirstClass object has not been constructed yet.

In your example, you wrote:

register for some events here.

that events will call someMethod and someMethod is calling FirstClass's method, before initializer list of FirstClass gets executed.

Since this means that the object's method will be called, then this is likely not valid, and will be Undefined Behaviour, since you cannot call method of an uninitialized object (unless all members that function relies upon are initialized).

ChrisMM
  • 8,448
  • 13
  • 29
  • 48
  • I updated the question, with detailed scenario. Also, code is compiling. please have a look. – Vishal May 30 '22 at 10:45
  • @Vishal, updated the answer. Based on your comments in the code, then it is not valid. – ChrisMM May 30 '22 at 13:30
  • It is not necessarily true that calling `someMethod()` would be undefined behavior. There is a well-defined order in how things are initialized. In particular, if all members of `FirstClass` that are used directly or indirectly by `someMethod()` are initialized using default member initializers and/or the member initializer list, or were initialied in the body of the constructor before `someMethod()` was called, then there is no undefined behavior. – G. Sliepen May 30 '22 at 14:17
  • @G.Sliepen , Yes I agree, in your case, there will not be undefined behavior. I am looking for the opposite case. where things doesn't go well and my FirstClass object is not completely initialized before `someMethod ` gets called. – Vishal May 30 '22 at 15:20
  • @G.Sliepen, true, updated to reflect that. – ChrisMM May 30 '22 at 15:27