The null check that follows is not redundant!



  •                 // The constructor actually sets up the renderer, so the null check
                    // that follows is not redundant!
                    TheUI = new AnonymizedClassName(newDatabase);
                   
                    if (null != TheUI)
                    {
     

    However, the 'new' operator is defined to return the newly constructed object or throw OutOfMemoryException if it fails. 

    I shudder to think what awaits beyond the next corner?  A race condition?  A misplaced assumption?

     

    [edit] 

    Here's the exciting conclusion

            static public AnonymizedClassName TheUI
            {
                get
                {
                    return sTheUI;
                }
                private set
                {
                    AnonymizedClassName toSet = value;
                    if (toSet != null && toSet.Database == null)
                        toSet = null;

                    if (sTheUI != toSet)
                    {
                        if (sTheUI == null)
                            TimerManager.InitializeTimer();
                        if (toSet == null)
                            TimerManager.KillTimer();

                        AnonymizedClassName oldTheUI = sTheUI;
                        sTheUI = toSet;
                        if (TheUIChanged != null)
                            TheUIChanged(oldTheUI, toSet);
                    }
                }
            }
     



  • @arty said:

                    // The constructor actually sets up the renderer, so the null check
                    // that follows is not redundant!
                    TheUI = new AnonymizedClassName(newDatabase);
                   
                    if (null != TheUI)
                    {
     

    However, the 'new' operator is defined to return the newly constructed object or throw OutOfMemoryException if it fails. 

    I shudder to think what awaits beyond the next corner?  A race condition?  A misplaced assumption?

     

    I once did something bad.

     

    It was back in the early days of c++ and we were all still using cfront.  Exceptions were a rarity back in those days.

     

     

    I had an object that did some initialisation in the constructor.  Yeh, I know that's bad now, but it was the first time I'd ever worked with the language.

     

     

     

    If the initialisation failed in the constructor, I did this:

        if (status < 0)
        {

            delete this

            this = NULL;

            return;
        }

    So you really did need to write

        cFoo *pFoo = new cFoo;

        if (pFoo == NULL)

        {

            // error handling

        }

    Yes.  I know. 

     

    I'm going to hell, aren't I?



  • @DaveK said:

    I had an object that did some initialisation in the constructor.  Yeh, I
    know that's bad now

    Wait, when is this bad since?

    And, regarding your snippet — could this really work? Even if Cfront allowed to change <font face="Courier New">this</font> (bleccchhh), wouldn't it only affect the implicit parameter passed to the constructor?



  • @Spectre said:

    @DaveK said:
    I had an object that did some initialisation in the constructor.  Yeh, I know that's bad now

    Wait, when is this bad since?

    Well, it's specifically initialisation operations of the kind that might fail, or might have dependencies on other parts of the application or system being up and running, and it's less of an issue nowadays where exceptions are implemented everywhere, but I was taught back then that as a style issue it's good to only do simple member initialisations in your c-tors and to have an "int Initialise()" member function that does the actual run-time initialisation and can return an error status.  Frex, if your object has to open and read a file, you pass in the filename to the c-tor, which stashes it away, but you don't try fopening the file until Initialise() time.   Like all style issues, it's not an absolute rule, but it mattered more when you couldn't just throw.  These days, I'd suppose it's less useful, but it's still a reasonable pattern to use in an application where you might have a lot of statically-constructed objects that might be c-tored in a fairly arbitrary order by the runtime startup.  E.g., I've heard of bugs where people use stdio in a c-tor and it all works fine whent they're new'ing stuff, but when they make an object static it can be c-tored at startup before the stdio library initialisation has run and the stdio calls fail mysteriously.

    @Spectre said:

    And, regarding your snippet — could this really work? Even if Cfront allowed to change <font face="Courier New">this</font> (bleccchhh), wouldn't it only affect the implicit parameter passed to the constructor?
     

    It did work, although probably only because the c-tor got inlined whereever it was invoked, but I tested it by forcing the failure and the code that had called new did indeed get a null pointer return.

    I never tried to understand how or why it worked, because Cfront-generated code is among some of the most nightmarish, monstrous, illegible bizarre gibberish machine generated spew that I have ever set eyes on in my life.  Hundred line statements composed of an impenetrable sequence of nested brackets and comma-separated expressions and synthetic symbol names that won't even fit on your screen in one go.  Sometimes my eyes still bleed at the thought!



  • @Spectre said:

    And, regarding your snippet — could this really work? Even if Cfront allowed to change <font face="Courier New">this</font> (bleccchhh), wouldn't it only affect the implicit parameter passed to the constructor?

    Did you mean the original snipplet? I see "Name{get{}set{}" there, so I guess it's C hash, not any incarnation of c++... then "new" will always be not null.

    Strange thing is that they blame constructor, but the problem is with property setter...



  • @viraptor said:

    @Spectre said:

    And, regarding your snippet — could this really work? Even if Cfront allowed to change <font face="Courier New">this</font> (bleccchhh), wouldn't it only affect the implicit parameter passed to the constructor?

    Did you mean the original snipplet?

    Nahh, he meant mine in the first reply. 



  • @Spectre said:

    And, regarding your snippet — could this really work? Even if Cfront allowed to change <FONT face="Courier New">this</FONT> (bleccchhh), wouldn't it only affect the implicit parameter passed to the constructor?

    Where do you think that implicit parameter is created?

    In the constructor. As a local variable. So you can do whatever you want to it during the constructor; the constructor owns it. At the end of the constructor, this local variable is tossed out as the return value, which works because it's a handle to a global memory block.

    Which is... you guessed it... the real WTF. When you really dig under the covers of C++ and see how enterprisey it is, you start to understand why the ANSI C folks like myself were hesitant to adopt it - some of the things it does are simply insane.

    But they work, so you learn to shrug your shoulders and work in it anyway. Especially when it will happily compile ANSI C without complaining. ;)



  • @CDarklock said:

    Where do you think that implicit parameter is created?

    In the constructor. As a local variable. So you can do whatever you want to it during the constructor; the constructor owns it. At the end of the constructor, this local variable is tossed out as the return value, which works because it's a handle to a global memory block.

    Wait wait wait wait wait. It cannot be this way. The constructor isn't the one to decide where the object is stored. For example:

    class A { /* stuff... */ };
    
    void F
    {
      A a;
    }
    

    Here, the position of the <font face="Courier New">a</font> object is predetermined, though it still needs to be passed to the constructor, so it will know where to construct the object. And if the object is dynamically allocated, <font face="Courier New">operator new</font> decides where to put it, not the constructor.

    And what's so enterprisey about C++?



  •  Looks like a race condition for me.



  • @Spectre said:

    Wait wait wait wait wait. It cannot be this way. The constructor isn't the one to decide where the object is stored.

    You're not understanding me. The constructor OWNS the one and only reference to the object between memory allocation (which is WHEN the object gets stored) and accessibility to other code. So if you "delete this" during the constructor, that's perfectly valid, because the constructor just has a handle to a memory block and - as you imply - does not know it's already allocated and can't be legitimately deleted. The constructor can't tell the difference between "new" and value-type declaration.

    The last time I read anything official about this, the behavior if your class A said "delete this" in the constructor was still undefined. But I haven't been particularly amused by language-lawyering for years.

    And what's so enterprisey about C++?

    See above.



  • @CDarklock said:

    You're not understanding me. The constructor OWNS the one and only reference
    to the object between memory allocation (which is WHEN the object gets
    stored) and accessibility to other code. So if you "delete this" during the
    constructor, that's perfectly valid, because the constructor just has a handle
    to a memory block and - as you imply - does not know it's already
    allocated and can't be legitimately deleted. The constructor can't tell the
    difference between "new" and value-type declaration.

    Well, yes. For a brief time, the constructor has the only pointer to the object. But it doesn't create it, it just uses it. So, when translating to C, the prototype of the constructor would be:

    void A_A (A * this, /* other arguments */);
    

    If you change this inside the constructor, the change is lost and has no further effect.



  • @Spectre said:

    Well, yes. For a brief time, the constructor has the only pointer to the object. But it doesn't create it, it just uses it. So, when translating to C, the prototype of the constructor would be

    ...wrong.

     A* A_A (A *this, /* other arguments */) { return a; }

    Once upon a time, C++ was simulated in ANSI C using macros.


  • Discourse touched me in a no-no place

    @CDarklock said:

    @Spectre said:
    Wait wait wait wait wait. It cannot be this way. The constructor isn't the one to decide where the object is stored. For example:

    class A { /* stuff... */ };
    
    void F
    {
      A a;
    }
    You're not understanding me. The constructor OWNS the one and only reference to the object between memory allocation (which is WHEN the object gets stored) and accessibility to other code. So if you "delete this" during the constructor, that's perfectly valid[...]

    In the snippet given, it is not legal in C++ for you to call

    delete this;
    anywhere (let alone the constructor) because the object is on the stack. (Nor would it be legal if created by new[ ], placement new, if it were a global, or a member of another object)



  • @CDarklock said:

    A* A_A (A this, / other arguments */) { return this; } // FTFY

    Okay, if Cfront did this, the snippet'd work. But why? You're not supposed to change <font face="Courier New">this</font>, anywhere, anytime. It makes no sense! After all, what would happen if the object wasn't allocated dynamically?


  • Discourse touched me in a no-no place

    @Spectre said:

    But why? You're not supposed to change <font face="Courier New">this</font>, anywhere, anytime. It makes no sense!
    Objects, under certain conditions, are allowed to 'commit suicide. Why you'd want to in general (as opposed to a saner method) is another matter..

    Placement <font face="courier new,courier">new </font>is another place where <font face="courier new,courier">this</font> is changed. 

    @Spectre said:

    After all, what would happen if the object wasn't allocated dynamically?
    That is not one of the certain conditions - see my other post.

     



  • @PJH said:

    Objects, under certain conditions, are allowed to 'commit suicide.

    Yeah, I know, but <FONT face="courier new,courier">this</FONT> (the pointer) is not changed in the process. If one deleted the object in the constructor, <font face="Courier New">new A</font> would still return an (invalid) pointer.

    @PJH said:

    Placement <FONT face="courier new,courier">new </FONT>is another place where
    <FONT face="courier new,courier">this</FONT> is changed. 

    Wait. What? I mean, I know what the placement <FONT face="courier new,courier">new </FONT> is, I don't see how can it change <FONT face="courier new,courier">this</FONT> — the object is simply constructed where it is told to.


Log in to reply