From -1675653459252189068
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: f78e5,50f0ad542032bb80
X-Google-Attributes: gidf78e5,public
X-Google-ArrivalTime: 1991-08-29 21:57:05 PST
Path: gmdzi!unido!mcsun!uunet!spool.mu.edu!agate!forney.berkeley.edu!jbuck
From: jbuck@forney.berkeley.edu (Joe Buck)
Newsgroups: comp.std.c++
Subject: Re: It's a lot worse than it sounds (was Re: The problem with temp...)
Keywords: nasty ugly pain operators strings owiee
Message-ID: <1991Aug29.230533.22972@agate.berkeley.edu>
Date: 29 Aug 91 23:05:33 GMT
References: <15751@goofy.Apple.COM> <15848@goofy.Apple.COM> <20797@alice.att.com>
Sender: usenet@agate.berkeley.edu (USENET Administrator)
Organization: University of California, Berkeley
Lines: 121

In article <15848@goofy.Apple.COM> mitch@Apple.COM (Mitch Adler) writes:
>> But this uses the copy constructor, and makes an extra copy (forcing
>> us to define MyObject pointer types if we want effeciency).
>> Ok, I can deal with that.

In article <20797@alice.att.com> ark@alice.UUCP () writes:
>So can some compilers -- the call to the copy constructor can
>often be optimized away.  This is especially likely if the
>function in question is inline.

I took your course a year and a half ago, Andy, and that's what you
told us.  Unfortunately, no one has taught cfront (as of version 2.1)
how to do it, even in simple cases like the following:

Here I have omitted many things that a real matrix class might have;
all that's here is the declaration of a copy constructor, a +=
operator, an assignment operator, and a + operator.

class Matrix {
private:
	double* data;
	int rows, cols;
public:
	Matrix();
	Matrix(const Matrix&);
	Matrix& operator+=(const Matrix&);
	Matrix& operator=(const Matrix&);
};

inline Matrix operator+(const Matrix& a,const Matrix& b) {
	Matrix tmp(a);
	tmp += b;
	return tmp;
}

void add(const Matrix& a,const Matrix& b,Matrix& c) {
	c = a + b;
}

If, in any case, a temporary can be optimized away, this is such a case.
If the compiler were allowed to assume that assignment and copy construction
mean assignment and copy construction, it could produce the equivalent of

void add(const Matrix& a,const Matrix& b,Matrix& c) {
	c = a;
	c += b;
}

The code generated by Sun's version of AT&T's cfront 2.1 for the
"add" function calls the copy constructor twice and does not optimize
away the temporary.  Here is a very-cleaned-up version of what is generated
(I rearranged the comma operators and re-named the temporaries so that
the code can be read by mere mortals; cfront would have no problem winning
the Obfuscated C contest):

char add__FRC6MatrixT1R6Matrix (__0a , __0b , __0c )
struct Matrix *__0a ;
struct Matrix *__0b ;
struct Matrix *__0c ;
{ 
	struct Matrix *pt1 ;
	struct Matrix *pt2 ;
	struct Matrix t3 ;
	struct Matrix t4 ;

	pt1 = __0a;
	pt2 = __0b;
	__ct__6MatrixFRC6Matrix (&t3, pt1);
	__apl__6MatrixFRC6Matrix (&t3, pt2);
	__ct__6MatrixFRC6Matrix (&t4, &t3);
	__as__6MatrixFRC6Matrix (__0c, t4);
}

When this code is handed to g++ (version 1.37.1), the exact same four
calls are produced in the same order.  However, g++ provides a language
extension: I could have written

inline Matrix operator+(const Matrix& a,const Matrix& b) return tmp(a) {
	tmp += b;
}

That is, I declare the return variable in the header and provide an
expression with the same syntax as those used to initialize the members
of a class when a constructor is used.  If I do this, one of the
copy constructors is eliminated.  We still don't have the ideal code;
we have the equivalent of

void add(const Matrix& a,const Matrix& b,Matrix& c) {
	Matrix tmp(a);
	tmp += b;
	c = tmp;
}

So the extension helps, but doesn't solve the problem: the compiler
must assume a particular relation between the copy constructor and
the assignment operator to eliminate the temporary.  Here's the Sparc
assembler code (with -O):

_add__FRC6MatrixT0R6Matrix:
        !#PROLOGUE# 0
        save %sp,-128,%sp
        !#PROLOGUE# 1
        add %fp,-32,%l0
        mov %l0,%o0
        call ___6MatrixRC6Matrix,0
        mov %i0,%o1
        mov %l0,%o0
        call _op$assign_plus__6MatrixRC6Matrix,0
        mov %i1,%o1
        mov %i2,%o0
        call _op$assign_nop__6MatrixRC6Matrix,0
        mov %l0,%o1
        ret
        restore

The name mangling is different, but you get the idea.

--
--
Joe Buck
jbuck@galileo.berkeley.edu	 {uunet,ucbvax}!galileo.berkeley.edu!jbuck	


