- How to call virtual functions in C++ - 6 Updates
- Zeroing in the constructor - 10 Updates
- How to call virtual functions in C++ - 5 Updates
- Ugly code to solve a combinatorial problem with an integer sum - 3 Updates
- OT Elite - 1 Update
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 12:26PM -0400 On 6/18/2015 12:22 PM, Stefan Ram wrote: > int main(){ A a; a.~A(); new( &a )B(); a.p(); } > Maybe some permission for this could even become > part of C++ one day. What problem does it solve that cannot be solved any other way? V -- I do not respond to top-posted replies, please don't ask |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 01:25PM -0400 On 6/18/2015 1:05 PM, Stefan Ram wrote: > indirection via pointers. Objects would not be > spread across the heap. And it would be natural > given that »is a« meaning of public inheritance. What I see you say here is that within the confines of a set of very strict requirements, we *might* get some advantage in terms of code execution speed. All that at the price of code maintainability and readability, not to mention debug-ability... Should probably work OK when programming a system that, once debugged and deployed, will never be touched again. In general, systems that I see developed live longer and mutate rather actively, being tended to by dozens of programmers at a time. I don't think that a feature should not be considered if its application is rare or to solve a niche problem not solved by other means. Take 'goto' for example, there are situations in which it is a convenient, if not elegant, approach. But introducing more complexity into the compiler by adding new features to the language, for the sake of unknown/unproven gains? > For example, usally every int value can be > represented by a corresponding double value. Right, usually. A 64-bit int cannot. > Insofar, an int »is a« double. An in fact, we /can/ > store int values in double objects. Not all of them, alas. > Often, in C++ > one tries to imitate features of primitiv types > when one builds class types. Yes, imagined features. Features that don't really give one any advantages. Distinct types are there for a reason. Don't use 'double' if you need an 'int'... > anyway. So when it already has this type information > at run time, it can use it as well to get the > type of an instance even without a pointer to it. I didn't quite get it where the last paragraph fits, sorry. My fault, I am sure. V -- I do not respond to top-posted replies, please don't ask |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 01:51PM -0400 On 6/18/2015 1:42 PM, Stefan Ram wrote: > So, I wondered whether we can use this information even > without a pointer, but instead, when *object is bound > to a name or is a sub-object of an array. Ah... OK. What you're after is heterogeneous collections of objects that are native arrays, for example, and not arrays of pointers. And you hope for the language support for that. My prediction is that it's *not* going to happen. V -- I do not respond to top-posted replies, please don't ask |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 18 01:57PM -0500 ram@zedat.fu-berlin.de (Stefan Ram) wrote in news:polymorphism- > might print »3« based on the type of the name »a«, but still > I /did/ observe that the implementation that I used printed »4«, > which - without »virtual« - might even be mildly surprising. That's interesting. Care to name the implementation? Formally it could print anything because your program invoked UB, but still interesting because UB occurs later (at destruction of the local variable). Cheers Paavo |
"A. Bolmarcich" <aggedor@earl-grey.cloud9.net>: Jun 18 02:18PM -0500 > native arrays, for example, and not arrays of pointers. And you hope > for the language support for that. > My prediction is that it's *not* going to happen. This topic brings to mind the comment by Dennis Ritchie about the C struct hack used in a program to implement a variable length array: "unwarranted chumminess with the C implementation". See <http://c-faq.com/struct/structhack.html> |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 18 03:19PM -0500 ram@zedat.fu-berlin.de (Stefan Ram) wrote in news:GCC-20150618211700 > 3.8p7 says that the name »a« can only be »used to manipulate > the new object, if« »the new object is of the same type as > the original object«. Yes, you are right. GCC is allowed to print or not print whatever it likes. |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 18 09:50AM -0500 =?UTF-8?B?TMWRcmluY3p5IFpzaWdtb25k?= <zsiga@nospam.for.me> wrote in >> If the code depends on all fields being 0, I don't see how >> setting all bytes to 0xff will help ;-) > It helps finding the un-initialized fields. No, it doesn't. Inside the constructor body most fields should be already initialized so this is just overwriting them with garbage. What one could do is to add custom operator new to the class and use the memset() command there. In the (end of the) constructor one could then use memchr(...,0xff,...) for finding any uninitialized fields (assuming no byte should actually be initialized to 0xff). Cheers Paavo |
"Lőrinczy Zsigmond" <zsiga@nospam.for.me>: Jun 18 05:15PM +0200 On 2015-06-18 16:50, Paavo Helde wrote: > No, it doesn't. Inside the constructor body most fields should be already > initialized so this is just overwriting them with garbage. Sounds bad to me: 'most of the fields'... If not 'all of them', then it means I cannot rely on this PS: Yossi Kreinin explained this clearer than I ever could: http://yosefk.com/c++fqa/ctors.html#fqa-10.6 |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 11:21AM -0400 On 6/18/2015 11:15 AM, Lőrinczy Zsigmond wrote: >> initialized so this is just overwriting them with garbage. > Sounds bad to me: 'most of the fields'... > If not 'all of them', then it means I cannot rely on this If the class is a pseudo-POD (all members are themselves PODs, and no virtual functions), then it's "all the fields", but the problem of stomping all over the already initialized ones still remains, of course. > PS: Yossi Kreinin explained this clearer than I ever could: > http://yosefk.com/c++fqa/ctors.html#fqa-10.6 V -- I do not respond to top-posted replies, please don't ask |
"Lőrinczy Zsigmond" <zsiga@nospam.for.me>: Jun 18 05:53PM +0200 > If the class is a pseudo-POD (all members are themselves PODs, and no > virtual functions), then it's "all the fields" Does it imply that OP's problem doesn't exist at all? "Turns out the program defines several large classes (~50 fields, mostly int's or int arrays, and a few pointers). The constructor is supposed to set everything to 0s and NULLs, but it misses a few fields, and the program blows up when it uses one of these uninitialized fields." |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 12:09PM -0400 On 6/18/2015 11:53 AM, Lőrinczy Zsigmond wrote: > is supposed to set everything to 0s and NULLs, but it misses a > few fields, and the program blows up when it uses one of these > uninitialized fields." The problem does exist, and, as usual is of their own making. Built-in types, pointers included, when default-initialized (as opposed to value-initialized), are left untouched. Memory is allocated for them, but the contents of the memory is left unchanged. That can be A BAD THING(tm) if you rely on the values to be specific, like 'NULL' for pointers or 0s for counters. The default-initialization (leaving the memory unchanged) is an optimization step. If you don't care what the value was before changing it in the course of your calculations, then why bother initializing it at all? Only initialize when you need particular values to actually be there. And if you didn't put any value in it, you can't rely on that value. Plain and simple. V -- I do not respond to top-posted replies, please don't ask |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 18 01:48PM -0500 Lőrinczy Zsigmond <zsiga@nospam.for.me> wrote in > If not 'all of them', then it means I cannot rely on this > PS: Yossi Kreinin explained this clearer than I ever could: > http://yosefk.com/c++fqa/ctors.html#fqa-10.6 Do not take this anti-FAQ too seriously. In proper C++ code most fields should still be initialized by initialization lists. There are some exceptions where this is too cumbersome. Also in C++03 arrays could not be initialized in initializer lists, but C++11 seems to have solved that. Cheers Paavo |
"Lőrinczy Zsigmond" <nospam@for.me>: Jun 18 09:15PM +0200 On 2015.06.18. 20:48, Paavo Helde wrote: > should still be initialized by initialization lists. There are some > exceptions where this is too cumbersome. Also in C++03 arrays could not be > initialized in initializer lists, but C++11 seems to have solved that. Sadly, what Yossi wrote is completely matches my own experiences: in the initializer-list you can only use a crippled-down version of the language; in the body of the constructor you can use the actual language. (PS: C++ is more than thirty years old, at this age it's a bit strange that we keep saying 'well the language is still not mature yet, but the next version of the standard will bring big changes') |
Paavo Helde <myfirstname@osa.pri.ee>: Jun 18 02:44PM -0500 =?UTF-8?B?TMWRcmluY3p5IFpzaWdtb25k?= <nospam@for.me> wrote in > in the initializer-list you can only use a crippled-down version > of the language; > in the body of the constructor you can use the actual language. I get a feeling that you might prefer to do things in overly complicated ways. This does not help with long-term codebase maintenance. > (PS: C++ is more than thirty years old, at this age it's a bit strange > that we keep saying 'well the language is still not mature yet, > but the next version of the standard will bring big changes') Who are the 'we' who do keep saying that? The C++11 version is 4 years in the past and there are no big changes planned for next releases. Anyway, it would be a sign of decline if a language would not keep pace with the new developments in hardware and computer science. It is a good thing threading was not standardized before one got full taste of multicore hardware, and it is a good thing that no GUI framework has been standardized up to now. Cheers Paavo |
legalize+jeeves@mail.xmission.com (Richard): Jun 18 08:13PM [Please do not mail me a copy of your followup] Paavo Helde <myfirstname@osa.pri.ee> spake the secret code >exceptions where this is too cumbersome. Also in C++03 arrays could not be >initialized in initializer lists, but C++11 seems to have solved that. C++03 introduced value initialization so you can initialize arrays to zero this way: class C { public: C() : a() {} private: int a[10]; }; C++98 does not have it. -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
legalize+jeeves@mail.xmission.com (Richard): Jun 18 08:15PM [Please do not mail me a copy of your followup] (Richard) legalize+jeeves@mail.xmission.com spake the secret code >C++03 introduced value initialization [...] As I don't have a C++03 standard to consult, I'm going by: <http://en.cppreference.com/w/cpp/language/value_initialization> -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Computer Graphics Museum <http://computergraphicsmuseum.org> The Terminals Wiki <http://terminals.classiccmp.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 18 04:22PM >class type changes its type and is now an object of DerivedClass. C++ is >a strongly typed language so the type of x does not change when you >assign a new value to it. When one uses public inheritance, this models an »is-a« relationship, so the idea that when y »is a« x it can be written into an x object is not that strange. Simplified, C++ guarantees only that an instance of the /same/ class can be placed into an object of a class. However, I believe that an implementation should also accept an instance of a class that has the same »memory layout«, and I believe that when two class specifiers are the same, but /only/ differ in their /name/ and in the contents of their /block statements/ then their instance should have the same memory layout. Therefore, I'd be surprise to see an implementation where the following does not print »4«. #include <iostream> #include <ostream> /* .------------------------------.--- only differences v v */ struct A { void p() { ::std::cout << "3"; }}; struct B { void p() { ::std::cout << "4"; }}; // no inheritance, no virtual! int main(){ A a; a.~A(); new( &a )B(); a.p(); } Maybe some permission for this could even become part of C++ one day. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 18 04:26PM >Therefore, I'd be surprise to see an implementation >where the following does not print »4«. Ok, I take this back. Without »virtual«, an implementation might print »3« based on the type of the name »a«, but still I /did/ observe that the implementation that I used printed »4«, which - without »virtual« - might even be mildly surprising. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 18 05:05PM >What problem does it solve that cannot be solved any other way? As I mentioned, programs run faster, when all objects of a sequence are in an array instead of irregularly spread across a heap. When one implements polymorphism via pointers, the naive solution for a sequence of instances is an array of pointers with objects spread in the heap. One can get better locality with custom allocators that use memory pools, but this is more effort. When it's possible to store an instance of a subclass directly into an object of a class then this would enable direct-polymorphism without pointers. This would allow one to implement a sequence of objects with an array, even when the entries have different subclasses. One would not be forced to use the indirection via pointers. Objects would not be spread across the heap. And it would be natural given that »is a« meaning of public inheritance. For example, usally every int value can be represented by a corresponding double value. Insofar, an int »is a« double. An in fact, we /can/ store int values in double objects. Often, in C++ one tries to imitate features of primitiv types when one builds class types. When a class has virtual members, C++ must store the type information as a run-time information anyway. So when it already has this type information at run time, it can use it as well to get the type of an instance even without a pointer to it. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 18 05:42PM >>type of an instance even without a pointer to it. >I didn't quite get it where the last paragraph fits, sorry. My fault, I >am sure. For a change, the following code is intended to be portable C++ again: #include <iostream> #include <ostream> #include <memory> struct object { virtual void showtype() = 0; }; struct A : public object { void showtype() { ::std::cout << "A\n"; }}; struct B : public object { void showtype() { ::std::cout << "B\n"; }}; int main() { ::std::unique_ptr< object >object; object = ::std::make_unique< A >(); object->showtype(); object = ::std::make_unique< B >(); object->showtype(); } it prints: A B This shows that the runtime system has stored /at run time/ the information whether the pointer »object« points to an instance of A or a an instance of B. This information could be stored in the pointer or in the pointee or somewhere else. I assume it's stored in the pointee. In this case, »*object« holds the information whether it is an A or a B. So, I wondered whether we can use this information even without a pointer, but instead, when *object is bound to a name or is a sub-object of an array. |
ram@zedat.fu-berlin.de (Stefan Ram): Jun 18 07:18PM >That's interesting. Care to name the implementation? Formally it could >print anything because your program invoked UB, but still interesting >because UB occurs later (at destruction of the local variable). I observed »4« with GCC 5.1.1 and »3« with GCC 4.7.2. The UB should already be there at the call of »p« because 3.8p7 says that the name »a« can only be »used to manipulate the new object, if« »the new object is of the same type as the original object«. Disclaimer: 3.8p7 does not say that the manipulation has UB otherwise (it uses »if«, not »/only/ if«), but just does not define a behavior, so it could still be that there is a behavior defined for this somewhere else, but I am not aware of such a definition. BTW, if the only problem would be the UB due to the implicit destructor call at the end of the block, this could be avoided by destructing the B instance and then placing an instance of type A into the storage again, which would make this destructor destroy an object of the original type. |
Victor Bazarov <v.bazarov@comcast.invalid>: Jun 18 10:53AM -0400 On 6/18/2015 10:33 AM, Victor Bazarov wrote: >> Nope. There is a bug somewhere... Back to find it... > Found the bug. It was performing the calculation out of order. Need to > start from the back. OK, here it is: =============================================================== >8 #include <list> #include <string> #include <iostream> #include <sstream> using namespace std; long primary(string const &sequence, remove_const<decltype(string::npos)>::type &end) { long val{0}; istringstream is(sequence); is >> val; end = sequence.find_first_not_of("123456789"); return val; } long calculate(string sequence) { auto sign = string::npos; long result = primary(sequence, sign); while (sign != string::npos) { char sg = sequence[sign]; sequence = sequence.substr(sign + 1); long rhs = primary(sequence, sign); if (sg == '+') result += rhs; else if (sg == '-') result -= rhs; } return result; } list<string> solutions(string const& sequence, long goal) { list<string> retval; if (!sequence.empty()) { auto ns = pow(3, sequence.length() - 1); for (int k = 0; k < ns; ++k) { int is = k; // generate the possible solution string possible; decltype(sequence.length()) ic = 0; ostringstream os; os << "possible solution # " << is; while (is > 0) { possible.push_back(sequence[ic++]); switch (is % 3) { case 1: possible.push_back('+'); break; case 2: possible.push_back('-'); break; } is /= 3; } while (ic < sequence.length()) possible.push_back(sequence[ic++]); if (calculate(possible) == goal) retval.push_back(os.str() + " : " + possible); // debugging } } return retval; } int main() { list<string> ls = solutions("123456789", 100); for (auto ss : ls) { cout << ss << endl; } } =============================================================== >8 possible solution # 909 : 123-45-67+89 possible solution # 1185 : 12-3-4+5-6+7+89 possible solution # 1416 : 12+3+4+5-6-7+89 possible solution # 1602 : 123+4-5+67-89 possible solution # 2560 : 1+2+3-4+5+6+78+9 possible solution # 3045 : 12+3-4+5+67+8+9 possible solution # 3205 : 1+23-4+56+7+8+9 possible solution # 3784 : 1+2+34-5+67-8+9 possible solution # 4744 : 1+23-4+5+6+78-9 possible solution # 5274 : 123+45-67+8-9 possible solution # 5823 : 123-4-5-6-7+8-9 :-) V -- I do not respond to top-posted replies, please don't ask |
kfrank29.c@gmail.com: Jun 18 08:56AM -0700 Hi Paul! On Thursday, June 18, 2015 at 6:09:34 AM UTC-4, Paul wrote: > Many thanks for your suggestions. I am trying to incorporate some of these ideas. > I'm finding it very difficult to make this work, though -- no easier to write than my previous attempt. > The problem is that (123 + 4) concatenated with 5 = 1275 which is not a legal sequence. Let me give a little more detail about what I was thinking. Let's use '_', '+', and '-' for concat, plus, and minus, respectively. So (just for shorthand, for this post) I could use "_+-++_++" to represent operations = { concat, plus, minus, plus, plus, concat, plus, plus }; This value of the data structure operations corresponds to a numerical value according to your rules for combining the digits 1 through 9. That is "_+-++_++" --> 12 + 3 - 4 + 5 + 67 + 8 + 9 I don't see any need to ever create a string (or vector or whatever) that actually contains "12 + 3 - 4 + 5 + 67 + 8 + 9" or ever work explicitly with the digits 1 through 9. (Of course you can work with the digits, numbers and sequences explicitly, along the lines, for example, of the approach Victor posted. What he says makes sense, and should work fine, too.) It is easy enough to loop over operations and calculate the value on the fly. Roughly: int value = 0; // accumulate final value here int number = 1; // first digit is always 1 if (operations[0] == concat) { number *= 10; number += 2; } // more stuff and actual loop here int sign = (operations[idx] == minus) ? -1 : +1; value += sign * number; > So we need to make sure to keep the sequences legal, and then I end up basically redoing my previous code. If you keep the actual digits implicit then any sequence of eight of the three operations is, by construction, legal. For example, a couple of pluses and minuses mixed up with some concats is automatically legal: "__+-+_-_" You just (implicitly) drop the operations in between the digits to get: "__+-+_-_" --> 123 + 4 - 5 + 67 - 89 It's then easy enough to initialize operations to a starting value (using my shorthand notation): operations = "________"; // eight concats and then write a loop that "increments" operations to cycle through all 6561 possible values. > Anyway, I'm very pleased to see someone else thought about the problem. I hope my suggestions make some sense to you. > Paul Happy Hacking! K. Frank |
Paul <pepstein5@gmail.com>: Jun 18 10:07AM -0700 On Thursday, June 18, 2015 at 2:31:17 PM UTC+1, Ben Bacarisse wrote: > overall plan first. > -- > Ben. Hi Ben, I got the problem from here: https://blog.svpino.com/2015/05/07/five-programming-problems-every-software-engineer-should-be-able-to-solve-in-less-than-1-hour Thanks, Paul |
Christopher Pisz <nospam@notanaddress.com>: Jun 18 09:43AM -0500 On 6/16/2015 6:44 PM, Jason C. McDonald wrote: > On 06/16/2015 04:24 PM, Christopher Pisz wrote: SNIP > near-pathologically stingy with memory and CPU cycles. > [Ahhhh, Elite. Side note, have you seen the open-source Elite-clone, > Oolite? Quite impressive.] I haven't. I shall check it out! -- I have chosen to troll filter/ignore all subthreads containing the words: "Rick C. Hodgins", "Flibble", and "Islam" So, I won't be able to see or respond to any such messages --- |
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