- c++ problem with dynamic and static object - 13 Updates
- #ifdef with enum member - 7 Updates
- Mutex when returning by value - 2 Updates
aotto1968 <aotto1968@t-online.de>: Jul 24 09:01PM +0200 Hi, a C++ class can be created on the "stack" or on the "heap" class A { int test; } // stack A myA(); // heap A* myA = new A(); Question: it is possible (with gcc) to find out if a instance was created on a "stack" or on a "heap" * ;-) |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jul 24 08:29PM +0100 On 24/07/2020 20:01, aotto1968 wrote: > Hi, > a C++ class can be created on the "stack" or on the "heap" I think you mean objects not classes. > } > // stack > A myA(); This is a function declaration not an object definition. > A* myA = new A(); > Question: > it is possible (with gcc) to find out if a instance was created on a "stack" or on a "heap" * Only by comparing address of object with the addresses of sentinal objects in automatic storage either side of the object of interest but doing things like this means you are Doing It Wrong (TM). Why do you care if an object is in automatic storage or in the freestore? /Flibble -- "Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin "You won't burn in hell. But be nice anyway." – Ricky Gervais "I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais "Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne asked on his show The Meaning of Life. "What will Stephen Fry say to him, her, or it?" "I'd say, bone cancer in children? What's that about?" Fry replied. "How dare you? How dare you create a world to which there is such misery that is not our fault. It's not right, it's utterly, utterly evil." "Why should I respect a capricious, mean-minded, stupid God who creates a world that is so full of injustice and pain. That's what I would say." |
Barry Schwarz <schwarzb@delq.com>: Jul 24 12:32PM -0700 On Fri, 24 Jul 2020 21:01:42 +0200, aotto1968 <aotto1968@t-online.de> wrote: >Question: >it is possible (with gcc) to find out if a instance was created on a >"stack" or on a "heap" * If you tell us why you need to know, we might be able to offer something meaningful. In your first example, myA is an object of type A. In your second example, myA is a pointer to an object of type A. When you write code, you should know the types of the variables you are using. If A is not trivial, you might consider evaluating sizeof(myA). For a pointer, the result should be 4 or 8. For an object, it should be greater. -- Remove del for email |
"Öö Tiib" <ootiib@hot.ee>: Jul 24 12:41PM -0700 On Friday, 24 July 2020 22:32:56 UTC+3, Barry Schwarz wrote: > If you tell us why you need to know, we might be able to offer > something meaningful. > In your first example, myA is an object of type A. No it is clearly a function without parameters returning A by value. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 24 01:08PM -0700 > On Fri, 24 Jul 2020 21:01:42 +0200, aotto1968 <aotto1968@t-online.de> > wrote: >>a C++ class can be created on the "stack" or on the "heap" An *object* can be created on the stack or on the heap. (Incidentally, the standard doesn't use those terms.) >>} >>// stack >>A myA(); This declares myA as a function. Drop the parentheses. > If A is not trivial, you might consider evaluating sizeof(myA). For a > pointer, the result should be 4 or 8. For an object, it should be > greater. There's no reason sizeof(myA) couldn't be the same as the size of a pointer. sizeof is not, except in some restricted cases, a good way to distinguish among types. As far as I know, there's no reliable way to determine whether a given address is the address of an object allocated on the stack or on the heap. There may be implementation-specific methods. It's typically not a good idea to (try to) write code that depends on this information. I suspect there's an underlying problem that has a better solution. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
"Öö Tiib" <ootiib@hot.ee>: Jul 24 01:11PM -0700 On Friday, 24 July 2020 22:01:53 UTC+3, aotto1968 wrote: > Hi, > a C++ class can be created on the "stack" or on the "heap" Life is not even near to that simple in C++. There is dynamic storage in C++ that default operator news are providing and it is close to what is often meant by "global heap". But user may replace operator news and then new is providing storage what user's version is providing. <https://en.cppreference.com/w/cpp/memory/new/operator_new> Rest of it is also way more fun than just "stack". There is static storage that is global, there is thread-local storage that is thread-specific, there is unspecified global storage where objects of thrown exceptions reside and there is automatic storage that is certainly not guaranteed to be in (thread-specific) stack but most often is. <erasing defective code> > Question: > it is possible (with gcc) to find out if a instance was created on a > "stack" or on a "heap" * This question is unanswerable as it is based on incorrectly simplified concept of the classifications of kinds of memory in C++ programs. |
Vir Campestris <vir.campestris@invalid.invalid>: Jul 24 09:55PM +0100 On 24/07/2020 20:29, Mr Flibble wrote: > objects in automatic storage either side of the object of interest but > doing things like this means you are Doing It Wrong (TM). Why do you > care if an object is in automatic storage or in the freestore? Sentinel objects won't help. There's no reason why the stacks for threads shouldn't be allocated on the heap - in fact I'd be surprised if they aren't. Andy |
Paavo Helde <eesnimi@osa.pri.ee>: Jul 25 12:18AM +0300 24.07.2020 22:01 aotto1968 kirjutas: > it is possible (with gcc) to find out if a instance was created on a > "stack" or on a "heap" * Only heuristically, and only in "nearby" stack, unless you have recorded this information in the object itself when creating it. A much more important question is why do you need this information? Most probably you want to be too clever for no good. E.g. there are reasons why std::bad_weak_ptr exception is thrown from shared_from_this if the original object is not managed by a std::shared_otr. Suggesting not to mess with stack/heap detection until you have understood those reasons. |
Juha Nieminen <nospam@thanks.invalid>: Jul 24 10:12PM > It's typically not a good idea to (try to) write code that depends on > this information. I suspect there's an underlying problem that has a > better solution. Maybe he just asked out of curiosity rather than need. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 24 03:27PM -0700 >> "stack" or on a "heap" * > This question is unanswerable as it is based on incorrectly simplified > concept of the classifications of kinds of memory in C++ programs. A more answerable question, similar to what the OP asked, might be: Is it possible, given a pointer value, to determine whether the object it points to has static, thread, automatic, or dynamic storage duration? I think the answer is basically "no". For a given implementation, it's likely to be possible to get *some* information. For example, on my system an object allocated with "new" has an address that's displayed as "0x5567e9909eb0", while a local object has an address that's diplayed as "0x7ffcaee7786c". That's probably good enough to distinguish between them *for debugging purposes*. But making a program's behavior depend on such a distinction is likely to be a bad idea. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
Daniel P <danielaparker@gmail.com>: Jul 24 03:46PM -0700 On Friday, July 24, 2020 at 3:29:16 PM UTC-4, Mr Flibble wrote: > On 24/07/2020 20:01, aotto1968 wrote: > > a C++ class can be created on the "stack" or on the "heap" > I think you mean objects not classes. If A is a class, "a A" is widely used as short for "an object of type A" (in C++) or an instance of class A (elsewhere.) It's a concession to readability with little danger of being misunderstood. Herb Sutter talks about "a std::vector" this way, as does Scott Meyers. Daniel |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 24 03:50PM -0700 > C++) or an instance of class A (elsewhere.) It's a concession to readability > with little danger of being misunderstood. Herb Sutter talks about "a > std::vector" this way, as does Scott Meyers. Informally Talking about "a std::vector" to mean "an object of type std::vector" is fine. Referring to an object as "a class", in my opinion, is not. Given std::vector<int> v; std::vector is a class. std::vector is a type. v is a std::vector. v is an object. v is not a class. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
Daniel P <danielaparker@gmail.com>: Jul 24 04:01PM -0700 On Friday, July 24, 2020 at 6:50:33 PM UTC-4, Keith Thompson wrote: > v is a std::vector. > v is an object. > v is not a class. Point taken :-) Daniel |
Juha Nieminen <nospam@thanks.invalid>: Jul 24 05:51AM > C++ already had two byte types too many - char, signed char, > and unsigned char. I don't know what the motivation was originally to have three distinct char types in C (from which C++ "inherited" them), but in a way it actually makes sense, perhaps serendipitously. The type 'char' is supposed to be the most efficient byte type for the target platform, either a signed one or an unsigned one. Most usually it should be preferred especially when dealing with strings, as long as one is aware that it can be either signed or unsigned, and doesn't make any assumptions either way. Curiously, this is not just theoretical. There is a *modern* very concrete example where this has bitten many a developer in the posterior, with code compiling but working incorrectly, because it wrongly assumes that 'char' is signed. Namely in ARM processors (at least the 32-bit ones) it so happens that an unsigned char is more efficient than a signed one, and thus most compilers (such as gcc) will use the 'char' type as an unsigned char. Most notoriously this happens when compiling for the Raspberry Pi (and probably other ARM-based systems). Many a C and C++ program out there doesn't work correctly for the Raspi because it wrongly assumes that 'char' is signed. I have encountered actual examples. (Most often this happens because of a if(c < 0), which obviously always evaluates to false if char is unsigned.) |
"Öö Tiib" <ootiib@hot.ee>: Jul 23 11:29PM -0700 On Thursday, 23 July 2020 17:07:43 UTC+3, Daniel P wrote: > It has to be > std::vector<std::byte> v = {std::byte{0x66},std::byte{0x6f}, > std::byte{0x6f}}; Yes and there is uint8_t that is in certain esoteric way better than all of those others. Also writing your own custom constexpr literal operator for std::byte will take considerable effort of yours. Plus if you have large fields of such binary data then also make compiling it slow. Plus if someone looks its code of it then they likely go ewwwww. Especially if the literal operator supports all the forms like: constexpr auto h = 0x66_b; constexpr auto d = 102_b; constexpr auto o = 0146_b: constexpr auto b = 0b1100110_b; static_assert(h == d and d == o and o == b); The idea of making raw bytes safer was actually good but it resulted with fifth inconvenient to use thing with bear traps attached. |
David Brown <david.brown@hesbynett.no>: Jul 24 08:45AM +0200 On 24/07/2020 07:51, Juha Nieminen wrote: > compilers (such as gcc) will use the 'char' type as an unsigned char. > Most notoriously this happens when compiling for the Raspberry Pi (and > probably other ARM-based systems). On most embedded targets, and most newer ABI's, plain char is unsigned because making "char" signed is a totally meaningless historical artefact from the days of 7-bit ASCII as the the only character set supported by C. The signedness of plain char is specified in the ABI, not given by the compiler - and pretty much every target except 32-bit Windows and a few embedded microcontrollers has a proper ABI that pretty much every compiler follows. (Though gcc, and some other compilers, may let you override the signedness of char with a command-line switch.) > actual examples. > (Most often this happens because of a if(c < 0), which obviously > always evaluates to false if char is unsigned.) Any code that makes any assumptions about the signedness of plain char is broken. If the signedness matters, make it explicit. (Usually int8_t and uint8_t make vastly more sense in code than "signed char" and "unsigned char". Or int_least8_t and uint_least8_t for maximal portability.) Unfortunately, you are right that people sometimes write such broken code. |
David Brown <david.brown@hesbynett.no>: Jul 24 08:48AM +0200 On 23/07/2020 16:07, Daniel P wrote: > It has to be > std::vector<std::byte> v = {std::byte{0x66},std::byte{0x6f}, > std::byte{0x6f}}; Why? I must be missing something here, besides my morning coffee. |
Bo Persson <bo@bo-persson.se>: Jul 24 09:52AM +0200 On 2020-07-24 at 07:51, Juha Nieminen wrote: > it should be preferred especially when dealing with strings, as long > as one is aware that it can be either signed or unsigned, and doesn't > make any assumptions either way. But people did. :-) Dennis Ritchie writes in a C history paper about char being unspecified, but just happened to be signed on their first implementations. However, as soon as they did their first unsigned version (for a new machine) it became apparent that users had already used char as a small signed integer. And now their programs didn't work. Bad compiler! So he added signed char to enable them to write more portable programs. Soon he had to also add unsigned char for users of the new machines, so they could move their programs to the older systems. |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 24 10:55AM -0700 Bo Persson <bo@bo-persson.se> writes: [...] > So he added signed char to enable them to write more portable programs. > Soon he had to also add unsigned char for users of the new machines, > so they could move their programs to the older systems. Hmm. I thought that unsigned char was added before signed char was. In K&R1 (1978), "unsigned" could only be applied to int, and the "signed" keyword didn't exist. K&R2 has the full modern set of integer types (other than long long). signed char isn't mentioned here: https://www.bell-labs.com/usr/dmr/www/chist.html [...] -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jul 24 10:58AM -0700 > actual examples. > (Most often this happens because of a if(c < 0), which obviously > always evaluates to false if char is unsigned.) One way this error can occur is if the program stores the result of getchar() in a char object rather than an int. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips Healthcare void Void(void) { Void(); } /* The recursive call of the void */ |
Juha Nieminen <nospam@thanks.invalid>: Jul 24 05:53AM > If I was writing supremely-portable code that I know might make its way to a less-than-perfect compiler, I might do something like this. > I found an alignment error in a PIC compiler a few years ago -- compilers aren't perfect. I don't think one should program trying to take into account hypothetical bugs in some random compiler. That doesn't make much sense. |
David Brown <david.brown@hesbynett.no>: Jul 24 10:32AM +0200 On 24/07/2020 07:53, Juha Nieminen wrote: >> I found an alignment error in a PIC compiler a few years ago -- compilers aren't perfect. > I don't think one should program trying to take into account hypothetical bugs > in some random compiler. That doesn't make much sense. No, you'd never get anything written. I once used a compiler (also for the PIC, which is a seriously brain-dead 8-bit microcontroller) that could handle structs, and arrays, but not arrays of structs or structs with arrays in them. You don't write code with such limitations unless you /really/ need to. There are occasional non-conformities that are not bugs, but active choices by compiler manufacturers, and portable code can therefore take them into consideration if the code needs to run on such systems. TI has a habit on their microcontroller tools of not zeroing uninitialised statically allocated data. The justification is that it can mean the time from microcontroller reset to the start of "main" is too long and can cause problems with watchdogs. This is nonsense, in my experience, and this misfeature is the cause of countless problems. Some portable embedded C code explicitly zero-initialises data in order to avoid problems if you use it with a TI compiler. (Another non-conforming "feature" that has a lot more justification is that for small 8-bit microcontrollers, "double" is often implemented as the same size as 32-bit float.) |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment