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-7-bit X-Google-Thread: f5d71,d275ffeffdf83655 X-Google-Attributes: gidf5d71,public X-Google-Thread: 1108a1,d275ffeffdf83655 X-Google-Attributes: gid1108a1,public X-Google-Thread: 115aec,d275ffeffdf83655 X-Google-Attributes: gid115aec,public X-Google-Thread: 103376,d275ffeffdf83655 X-Google-Attributes: gid103376,public X-Google-Thread: 109fba,d275ffeffdf83655 X-Google-Attributes: gid109fba,public X-Google-Thread: 146b77,d275ffeffdf83655 X-Google-Attributes: gid146b77,public X-Google-Thread: f849b,d275ffeffdf83655 X-Google-Attributes: gidf849b,public X-Google-Thread: 101b33,d275ffeffdf83655 X-Google-Attributes: gid101b33,public From: "Martijn Lievaart" Subject: Re: Dynamic memory? (was Re: Ada vs C++ vs Java) Date: 1999/01/18 Message-ID: <77vshi$lg@news3.euro.net> X-Deja-AN: 434069562 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-MimeOLE: Produced By Microsoft MimeOLE V4.72.3110.3 Organization: EuroNet Internet 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 in message <36a357bb.24173519@news.demon.co.uk>... >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. There is no parallel in C to a >constructor. The only stack usage in C results from function calling. > [ I'll respond to your points in order thay are made, however it seems the main stumbling block is that you assume a compiler cannot know the size of an object in advance. We'll come to that so please read all before responding to the first parts. ] You confuse calling a constructor and allocating memory for an object. The objects are allocated on the stack, just the same as a struct in C. After that the constructor is called, on these raw memory bytes. *No* dynamic allocation, it is known in advance. And yes, operator overloading can result in more stack usage then doing it another way, but it is still stack memory and known in advance. You say that the temporaries are created as a result of call to a constructor. That is correct. However, constructing and allocating an object are very different things. An object is only created on the heap if someone calls new. And that someone is *not* the compiler. Why would it? It knows what object to allocate, knows the size. Stack is so much faster than heap, no reason to call new. (To be honest, the temporaries might be allocated on the heap, the standard doesn't forbid it. Just any compiler that does so will have a very limited life span. Would be the same as a C compiler that allocated all automatic variables on the heap. C-standard allows that too.) >>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. > And the same holds for C++. It is *exactly* the same as C, except for a constructor call. And that is an ordinary function call "under the hood". Think of it as the following C code. struct S { int i; }; void f() { struct S s; init_S(&s); /* do something with s */ } init_S is the constructor call. The equivalent C++ is really equivalent. The space for the object in C++ is allocated on the stack in *exactly* the same way as the struct above in C, the the constructor is called. There is nothing magical here. Temporaries are handled in *exactly* the same way, they are just unnamed, as are temporaries in C. You may say, but the object is returned! It cannot be allocated the same as struct S as it originates in another function.... Read on, it'll become clear. >> 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. > You misread me. The fact that the compiler tells you this is not a convenience, but *you* cannot know by examining the source as the C compiler may have to generate temporaries. So the compiler has to tell you (or the linker). So it is not an automation to relieve the programmer from calculating it, you just cannot tell. Of course you have to know your program will fit and have to allocate stack accordingly. (hey I did dos once to long ago. There was no compiler support to figure out how big the stack had to be, I'ld have died for a compiler that told me). >>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. > >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. > Yes it does. It always does. It knows the type of the object, thus knows it's size, thus it knows how many bytes to pre-allocate in the stackframe. Try it, write a C++ program that does this and look at the assembly. It might be enlightning. Why do you think it doesn't know the size in advance? It's a Complex. Presumably that is a struct (class) with two doubles in it. Double is (say) 8 bytes. Complex is 16 bytes. Simple. Overloaded operators have to return something. The sizeof() this "something" is what is allocated on the stack as a temporary. It is stated in the source what this "something" is. In the example we're talking about, it is an object of type Complex. Remember, objects in C++ are just structs with a funny syntax, nothing magical going on here. You know the size of a struct in advance, don't you? Well the same with classes. Maybe you should look at a C function that returns a struct. How does the C compiler manage that? The return value (assuming it doesn't fit registers) must have some storage allocated for it. Commonly it is done on the stack (thread-safe) and a hidden parameter is passed to the function or it is pre-allocated as a global (thread-unsafe) and the return value is actually a pointer to this pre-allocated struct. This is equivalent to what happens in C++. Actually, it is exactly the same! >> 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! > No you haven't. You keep repeating operator new is called as a result of operator overloading, but you fail to see this is not necessery to do so and therefore isn't done. You obviously haven't tried any of this stuff because simple experiments will show that operator new isn't called and looking at the assembly output will show that it is allocated in advance in the stackframe. No magic here, just simple assembly. >> 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). So there is an explicit >call to allocate memory. The point I am trying to make is how do you >work out how much memory is used by a C++ program? > Explicit as in calling malloc or using new and doing it yourself explicitly. The operator + doesn't have to call new, nor does it do it. The point I'm trying to make is that you are telling that C++ calls operator new behind your back and I'm trying to show that it doesn't nor has to (and even cannot, but that's a whole other issue we had better not get into). What is it with the friend? I don't get that. No Complex class I've ever seen had to be friends with new. In fact no class I've ever seen except classes related to memory management itself (and these are hairy, an advanced topic and generally a bad idea). Nothing in C++ requires this afaik. Or do you mean that the operator has to be a friend of Complex if it is not a member? That is only to access Complexes private parts and has nothing to do with memory management at all. (Indeed I argue that the friend keyword be replaced by lover, as it allows access to the private parts ;^>). So how do you work out how much memory your program uses? Exactly the same as in C. Except that C++ compilers are not as mature and may not do the calculations required to tell the linker how many stack to put aside. But there is no reason it cannot be done. In fact I have done it in embedded (C++) programming, but by hand. (What a satisfying sight to see something you programmed on a lot of counters all over the Netherlands. I couldn't resist. Nope they didn't change the debug passwords. Fun!). >>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. > You are confused about what C++ will "do for you". It does not do any of these magical things you atribute it with. In fact, it is all very simple. Operator overloading has problems because it will generate temporaries on bad compilers. Even on these bad compilers, these temporaries are placed on the stack as any other temporary. The current standard has some expilicit stuff about optimizing these temporaries away (see also comp.std.c++, thread " Optimization questions (was Re: Returning locally created variables)"). And yes, C++ allows you to create code that will do a lot of things behind your back. That's the beauty of it. It may also allocate temporaries, but always on the stack. It may do some other surprising things. But a programmer who doesn't know these is not a good C++ programmer. A C++ programmer has to know as much what his program does in terms of assembly as a C programmer does (which may be very little for most of us and a lot upto exactly for others). And again the same goes for C. If you don't know that passing a struct to a function will allocate a copy, you are in for some nasty surprises. Nothing magical here, just the basic stuff. If you think that allocating a pointer will automatically allocate memory (an error I see daily on c.l.l.c-c++) you are in for some rude surprises. Same with C++. If you think the C++ compiler will automagically call new for you, you are in for some nice(?) surprises. You seem not to know C++ and operate on lore. Where did you get this info? A good C++ programmer knows what his code does, and knows when he has to know it to-the-byte. Embedded programming generally means you've got to know to-the-byte so if you do Embedded-C++, you have to know and you can. C++ doesn't hide these things from you, although it takes some time to learn exactly what the language does. And yes, there is room for a compiler to implement some stuff the way it sees fit. That may not be acceptable for an embedded system. I know, I've programmed embedded systems in C++. However, the things you are objecting to are exactly the same in C as in C++, just different syntax and possibly some extra temporaries because the compiler is not smart enough to optimize them away. (Of course there are a lot of bad C++ programmers..... well there where a lot of bad C programmers before C++ got hot. I know, I was one back then ;^>). I don't think C++ encourages such coding styles, btw. Operator overloading is a tool. Malloc is a tool. Use it when apropriate. Hey even VB is a tool ;^>! Using it when not apropriate is a telltale sign of an inexperienced or bad programmer. I used it once in the preceding year. >> I remember >>Stroustrup commenting on this as one of the myths hardcore C programmers >>have against C++, but I'm to lazy to look it up right now so don't quote me >>on it (yet). > >I'd love to see it if you can find it. I'll try to find it.... > >>Mind you, I'm not saying C++ is a better or even viable alternative, but I >>do want to get these myths out of the way. > >Calling it a myth does not make it go away ;-) > It's not there, so it must be a myth ;^> Martijn -- My reply-to address is intentionally set to /dev/null reply to mlievaart at orion in nl