From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII X-Google-Thread: f849b,d275ffeffdf83655 X-Google-Attributes: gidf849b,public X-Google-Thread: f5d71,d275ffeffdf83655 X-Google-Attributes: gidf5d71,public X-Google-Thread: 115aec,d275ffeffdf83655 X-Google-Attributes: gid115aec,public X-Google-Thread: 101b33,d275ffeffdf83655 X-Google-Attributes: gid101b33,public X-Google-Thread: 109fba,d275ffeffdf83655 X-Google-Attributes: gid109fba,public X-Google-Thread: 146b77,d275ffeffdf83655 X-Google-Attributes: gid146b77,public X-Google-Thread: 103376,d275ffeffdf83655 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,d275ffeffdf83655 X-Google-Attributes: gid1108a1,public From: James Kanze Subject: Re: Dynamic memory? (was Re: Ada vs C++ vs Java) Date: 1999/01/18 Message-ID: <36A36D94.31CBA05C@dresdner-bank.com> X-Deja-AN: 434058561 Content-Transfer-Encoding: 8bit References: <369C1F31.AE5AF7EF@concentric.net> <369DDDC3.FDE09999@sea.ericsson.se> <369e309a.32671759@news.demon.co.uk> <369F0592.94F9DDDA@dresdner-bank.com> <77pnr4$ch3$1@newnews.global.net.uk> <36a3281a.11980677@news.demon.co.uk> <77vclp$rme@news3.euro.net> <36a34176.18473393@news.demon.co.uk> <77vi92$944@news3.euro.net> <36a357bb.24173519@news.demon.co.uk> X-Accept-Language: fr,en,de Content-Type: text/plain; charset=iso-8859-1 Organization: Dresdner Bank Mime-Version: 1.0 Newsgroups: comp.lang.ada,comp.lang.c++,comp.vxworks,comp.lang.java,comp.java.advocacy,comp.realtime,comp.arch.embedded,comp.object,comp.lang.java.programmer Date: 1999-01-18T00:00:00+00:00 List-Id: John Birch wrote: |> On 18 Jan 1999 14:59:46 GMT, "Martijn Lievaart" |> wrote: |> >>Complex one (1), Complex two (2), Complex three (3), Complex four (4); |> >>Complex Sum; |> >>Sum = one + two + three + four; |> >>If Complex is a class with an overloaded + operator, I get temporary |> >>objects generated (possibly at the compiler's option) in the above |> >>statement. Since it can be written as; |> >>Sum = operator + (operator + (operator +(one, two), three), four); |> >>Now try telling me how to calculate a worst case C++ memory |> >>requirement. |> >It is more difficult, but the temporaries in the example above are also |> >allocated on the stack, so the same argument as in the C case still holds. |> No, it does not! The temporary objects created above are as a result |> of calls to an object constructor. The temporary objects are allocated on the stack by the compiler. The constructor has nothing to do with allocating the object itself. It is just another function that is called on the "object" (with the difference that if it exists, it is the first function called, and so must be able to deal with raw memory). |> There is no parallel in C to a |> constructor. The only stack usage in C results from function calling. The constructor is a function; the only stack usage in C++ results from function calling. |> >In fact, the C compiler is also free to generate temporaries on the stack |> >and often does so. |> Whilst it may use the stack space for temporary values, this space is |> pre-allocated in the stack requirements for any given function call. A |> C compiler AFAIK will never extend the size of the stack frame within |> a given function. It depends on what you mean by extending the size of the stack frame. Every C compiler I've seen pushes arguments onto the stack, which is effectively increasing the size of the stack frame. These arguments are removed when the function returns. Every C++ compiler I've seen does likewise. No C compiler I've seen changes the size of the stack other than this (at least when compiling C90 conformant code). No C++ compiler I've seen either. The only exception I've seen is to support variable length arrays. Which only exist in C, and then, only in the current committee draft (the basis of C99 or C20, depending on ISO paperwork). |> > I think that the main reason why the compiler/linker will |> >calculate the maximum stacksize for you (the embedded scenario you |> >described) is not as a convenience to users, but because the user cannot |> >know in advance what stack usage his program has. Only the compiler knows |> >this. |> No, the main reason is exactly as I stated it, it is to tell embedded |> programmers how much stack space a program will use. The value of the |> stack space as calculated by the compiler is used by the linker to |> locate various portions of the code generated by the compiler and to |> check that heap, initialised data and stack space do not overflow |> available memory. There is absolutely no reason why a C++ compiler could not do the same. Perhaps they do; I've not used C or C++ on systems where it mattered. |> >Let me repeat, this is exactly the same as a C compiler. F.i. take the |> >following code. |> >int f(int i1, int i2, int i3) |> >{ |> > return i1+i2+i3; |> >} |> >On a register poor machine (not likely, but it might) this certainly will |> >allocate temporaries on the stack. Very unliky, since you don't need any temporaries. You need sub-expressions to trigger spilling, e.g. (i1 + i2) * (i3 + i4). The compiler needs to save the results of one of the sub-expressions while it calculates the other. |> Yes it might, but the compiler will include any stack space it is |> using as registers into the stack requirements for function f(). In |> the C++ example the compiler may not know how big the temporary |> objects are going to be. The expression sizeof(T) is still a compile time constant in C++. As it used to be in C. |> > This is exactly the same as the example that started this thread, |> >only no function calls to an user defined operator but a hardcore |> >integer-add instruction. |> As I've shown it is in fact different! Where have you shown this? |> > But *no more* dynamic memory |> >allocation than in this C example. (yeah, user defined operators are |> >function calls, so these take a stack frame, but that is the same as you |> >calling a function in C, i.e. predictable and reportable by the compiler). |> >Not even mentioning the fact that a good (embedded) C++ compiler might even |> >only use registers in most cases. |> >In fact, C++ will *never* dynamically allocate memory on your behalf if you |> >don't explicitly tell it to. |> This depends on your definition of explicit. In order to code the |> above example, the operator + function has to call operator new |> (indeed it has to be a friend function too). Why? I've written plenty of such classes in C++, and they've never called new. And the C++ language *never* allows a call to new unless the programmer has written one (or called a library function which is allowed to call new). The normal way of implementing return of a complex type in C++ is exactly the same as the normal way of implementing return of a struct in C: the calling function reserves the space (of a constant size) on the stack, and passes an extra, hidden parameter to the called function, to tell it where to put the return value. |> So there is an explicit |> call to allocate memory. Where? A typical implementation of operator+( Complex , Complex ) will simply be: return Complex( op1.real + op2.real , op1.imag + op2.imag ) ; No new anywhere. |> The point I am trying to make is how do you |> work out how much memory is used by a C++ program? Exactly the same way you work out how much memory is used by a C program. |> >The RTL, maybe, will ask specificly, but not |> >the language itself. And that is *exactly* the same as C. |> It is a language feature (operator overloading) that creates the |> problem in the first place by encouraging such coding styles. One of |> the core tenets of C programming is the 'nothing up my sleeve' |> approach, C++ does not have this requirement that the programmer has |> visibility of every action taken by the code. This I feel is a major |> disadvantage when coding for resource limited hardware. This is a separate argument. Not totally true, of course -- the first C implementations I used regularly generated hidden function calls for arithmetic on longs or any floating point. Operator overloading does mean one more thing to pay attention to, and should be used very sparingly. But what is the difference between C++, where Complex is a class defined in the library, and C, where it is a built-in type (which no doubt generates calls to library functions for multiplication or divide)? -- James Kanze GABI Software, S�rl Conseils en informatique orient� objet -- -- Beratung in industrieller Datenverarbeitung mailto: kanze@gabi-soft.fr mailto: James.Kanze@dresdner-bank.com