[interfacekit] Re: oddish?

On 2004-02-16 at 17:28:58 [+0100], Marcus Overhagen wrote:
> > > On Mon, 16 Feb 2004, Adi Oanca wrote:
> > > 
> > > > int main()
> > > > {
> > > > [...]
> > > > lay->Invalidate(BRect(225,10,350,400));//BRegion(lay->Bounds()));
> > > > [...]
> > > > }
> > > >
> > 
> >  As Ingo pointed out, this is perfectly valid C++.  I'd like to point out
> > that this the above is an example of something you should try to avoid.
> > Not because of the BRect->BRegion thing, but because some compilers
> > (like ours) have an issue with the scope of temporaries that are used as
> > arguments.  This only happens sometimes and I'm not really sure under
> > what circumstances this turns into an error.  (runtime error! :-( )  But 
> > it
> > is safer to do the following:
> > 
> > BRect rect(225,10,350,400);
> > lay->Invalidate(rect);
> 
> According to Stroustrup, this is complicated.
> Explicit calling of the constructor of an Object that
> is used to initialize a const reference is allowed.
> 
> Like in this example:
> 
> void foo(const BString &);
> 
> foo(BString("test"));
> 
> As long as a temporary object is bound to a const reference,
> it won't be destroyed.
> 
> But if the temporary opject is only used inside an expression,
> it will be destroyed at the end of the expression. Example:
> 
> const char * str = BString("test).String();
> 
> At the end of the "BString("test).String()" expression, the
> temporary BString object is destroyed, and the pointer
> that was returned by String() is no longer valid, as the
> object is missing.
> 
> The same applies if such a temporary object is used as
> a function parameter, as long as the temporary object
> is not bound to a const reference parameter.
> 
> Here the object is only temporary, and since it is used in a
> full expression, it will be destroyed after the end of the full
> expression. Consider this example:
> 
> void bar(const char *);
> 
> bar(BString("test").String());
> 
> A temporary BString object is created, initalized with "test".
> Then a pointer to the (copy) of the string inside the BString
> object is returned by the String() function, and pushed on the
> stack. Now the expression is evaluated, and the temporary
> BString object is destroyed. Now the function bar() is executed,
> using the pointer that is on the stack, but no longer valid since
> the temporary object was already destroyed.

I don't believe this is true. AFAIK temporary objects are not destroyed at 
the end of an expression, but at the end of a statement; that is in your 
example after bar() returned. Attached is a little program that executes two 
tests, which demonstrate that behavior. The second test is of particular 
interest, since it also shows how buggy our gcc is -- the B destructor is 
invoked twice on the same object. mwcc does it correctly though, destroying 
B after A.

CU, Ingo


#include <stdio.h>

class A {
public:
        A()
        {
                printf("A::A()\n");
        }

        ~A()
        {
                printf("A::~A()\n");
        }

        const char* m()
        {
                return "Hello World!";
        }

};

class B {
public:
        B()
        {
                printf("B::B()\n");
        }

        ~B()
        {
                printf("B::~B()\n");
        }

        const char* m()
        {
                return "Hello World!";
        }

};

const char*
bar(const char* a)
{
        printf("bar(%s)\n", a);
        return a;
}

A
foo(B b)
{
        printf("foo()\n");
        return A();
}


int
main()
{
        printf("test 1\n");
        printf("------\n");
        bar(A().m());
        printf("\ntest 2\n");
        printf("------\n");
        bar(foo(B()).m());
        return 0;
}


Other related posts: