- Let'me learn. - 5 Updates
- A fixed string - 6 Updates
- Comparing this Pointer to Null - 8 Updates
- Release: stdlib v1.0-beta - 1 Update
woodbrian77@gmail.com: Jul 04 06:28PM -0700 On Monday, July 3, 2017 at 2:58:54 PM UTC-5, Öö Tiib wrote: > Usually automatic variable or direct data member, 'std::optional', > 'std::array', 'std::vector' or 'std::make_unique' are better, safer and > more efficient to use at that spot. I'm looking forward to being able to write: ::std::unique_ptr request{new cmw_request(recbuf)}; rather than: auto request=::std::make_unique<cmw_request>(recbuf); in C++ 2017. Support for this isn't widely available yet, though, from what I can tell. Brian Ebenezer Enterprises - In G-d we trust. https://github.com/Ebenezer-group/onwards |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 05 04:14AM +0200 > auto request=::std::make_unique<cmw_request>(recbuf); > in C++ 2017. Support for this isn't widely available > yet, though, from what I can tell. You can write that first declaration today, and you could from and including C++11. Using `make_unique` only matters when there are two or more `unique_ptr` initializations in the same expression, since then a non-smart compiler might let the `new` expressions be evaluated before the `unique_ptr` initializations, and then what if the second `new` fails? Leak. Ouch. As I understand it C++17 will make that use of `unique_ptr` unnecessary, by constraining the evaluation order slightly. Cheers!, - Alf |
woodbrian77@gmail.com: Jul 04 10:29PM -0700 On Tuesday, July 4, 2017 at 9:14:26 PM UTC-5, Alf P. Steinbach wrote: > > yet, though, from what I can tell. > You can write that first declaration today, and you could from and > including C++11. I have the above two lines here: https://github.com/Ebenezer-group/onwards/blob/master/tiers/cmwAmbassador.cc at lines 270 and 271. One of the lines is commented out because I don't know of a compiler that accepts it right now: //::std::unique_ptr request{new cmw_request(recbuf)}; This thread is related: https://groups.google.com/forum/#!topic/comp.lang.c++/m43-E2_msOw Brian Ebenezer Enterprises http://webEbenezer.net |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 05 03:37PM +0200 > //::std::unique_ptr request{new cmw_request(recbuf)}; > This thread is related: > https://groups.google.com/forum/#!topic/comp.lang.c++/m43-E2_msOw I failed to see that there isn't any template argument for `unique_ptr`. I think, from the reference to old discussion, that you're envisioning constructor template argument deduction, as in <url: http://open-std.org/JTC1/SC22/WG21/docs/papers/2015/n4471.html>. From what I understand of that paper they intend that the expression `unique_ptr{ new T }` should be well-defined, deduced as `unique_ptr<T>{ new T }. But that wouldn't allow you to omit template argument in the type in a declaration. You could use `auto` though. * * * The paper starts with the following example, which I've taken the liberty of reformatting to more readable for me: vector<int> vi1 = { 0, 1, 1, 2, 3, 5, 8 }; vector<int> vi2; template< class Func > std::mutex m; unique_lock<std::mutex> ul( m, std::defer_lock ); class Foo() { public: Foo( Func f ) : func( f ) {} void operator()(int i) { os << "Calling with " << i << endl; f(i); } private: Func func; mutex mtx; }; I /think/ that the author intended for the class to be a template, starting with `template< class Func >`. Cheers!, - Alf |
woodbrian77@gmail.com: Jul 05 12:29PM -0700 On Wednesday, July 5, 2017 at 8:38:15 AM UTC-5, Alf P. Steinbach wrote: > `unique_ptr{ new T }` should be well-defined, deduced as `unique_ptr<T>{ > new T }. But that wouldn't allow you to omit template argument in the > type in a declaration. You could use `auto` though. Is this what you mean by using auto: ::std::unique_ptr<auto> { new T} ? Several months ago I applied a patch from professor Spertus to a version of g++. After doing so I was able to compile the line as I've written it here previously: :std::unique_ptr request{new cmw_request(recbuf)}; . Professor Spertus saw my code and didn't say, "Hey, you need to add auto ..." Brian Ebenezer Enterprises - Enjoying programming again. http://webEbenezer.net |
woodbrian77@gmail.com: Jul 04 07:41PM -0700 There's const_string: http://conststring.sourceforge.net/ and fix_str: https://www.codeproject.com/articles/12024/fix-str-an-almost-immutable-string-class-in-c I'm not sure why something like this hasn't been more popular, so I decided to give it a shot also. Small string optimization goes up to around 24 characters I think. I think this could be helpful for cases that are bigger than that. Please let me know what you think about it. I may add some assignment operators. #pragma once #include"ErrorWords.hh" #include"marshalling_integer.hh" #include"SendBuffer.hh" #include<array> #include<string_view> #include<string.h> namespace cmw{ template<int N> class fixed_string{ int length; ::std::array<char,N> str; public: explicit fixed_string (char const* s):length(::strlen(s)){ if(length>N-1)throw failure("fixed_string ctor"); ::strcpy(&str[0],s); } explicit fixed_string (string_view s):length(s.length())){ if(length>N-1)throw failure("fixed_string ctor"); ::strncpy(&str[0],s.data(),length); str[length]='\0'; } template<class R> explicit fixed_string (ReceiveBuffer<R>&buf):length( marshalling_integer(buf)()){ if(length>N-1)throw failure("fixed_string stream ctor"); buf.Give(&str[0],length); str[length]='\0'; } void Marshal (SendBuffer& buf,bool=false)const{ marshalling_integer(length).Marshal(buf); buf.Receive(&str[0],length); } char const* c_str ()const {return &str[0];} char operator[] (int index)const {return str[index];} }; using fixed_string_60 = fixed_string<60>; using fixed_string_120 = fixed_string<120>; } I haven't checked this in yet, but probably will over here: https://github.com/Ebenezer-group/onwards Brian Ebenezer Enterprises - Enjoying programming again. http://webEbenezer.net |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 05 07:32AM +0200 > helpful for cases that are bigger than that. > Please let me know what you think about it. I may add some > assignment operators. I never used any of the above. But I already used immutable string classes in larger projects. Well I think that strings of statically typed size are of little use unless you intend to port very old code from Cobol or something similar. On the other side /immutable/ strings /are/ very useful, especially in multi-threaded environments because they are intrinsically thread-safe for read operations. But if you talk about immutable strings you need always talk about /mutable/ string references, too. They are essential to use the immutable strings. They provide the object lifetime management. And, of course, they are /not/ intrinsically thread-safe. Most of the time the programmer will deal with these string references rather than the internal string behind the scenes. Writing an immutable string class is straight forward. But writing a reasonably smart, mutable wrapper around the string references /is/ an advanced topic, at least if you include thread-safety with reasonable performance. The basic idea behind this concept is to keep any non-mutating operations to the strings content constant time, including assignment (of the references) and including thread-safe read and write of the references. In fact it can be implemented lock-free and even without CAS loops or spin-locks. BTDT If you have gone this way it opens the door to deduplication of string values in memory and in memory database applications with rather high performance. BTDT, too. Marcel |
peter koch <peter.koch.larsen@gmail.com>: Jul 05 02:01AM -0700 Den onsdag den 5. juli 2017 kl. 07.32.43 UTC+2 skrev Marcel Mueller: > > helpful for cases that are bigger than that. > Well I think that strings of statically typed size are of little use > unless you intend to port very old code from Cobol or something similar. Why? I guess it very much depends on your application area. Personally, I have much use of strings with a static maximum size, using them whenever I program against an interface which defines maximum sizes for I/O. This enables me to verify my strings size at creation rather than when I need to serialise it (putting it on a display or sending it over a wire). Internally, my size-limited strings are represented as a std::(w)string or as a boost::small_vector (if I remember the name correctly). The same is the case for any array I use representing "external" data. > multi-threaded environments because they are intrinsically thread-safe > for read operations. > Marcel Certainly! Immutable and hopefully also constexpr so that I can manipulate them while compiling. /Peter |
Dombo <dombo@disposable.invalid>: Jul 05 08:06PM +0200 Op 05-Jul-17 om 7:32 schreef Marcel Mueller: > If you have gone this way it opens the door to deduplication of string > values in memory and in memory database applications with rather high > performance. BTDT, too. In many programming languages such as C#, Java and Python strings are immutable, which is a very useful property indeed. It would be a nice if standard library supplied a immutable string class of its own. |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 05 08:46PM +0200 On 05.07.17 11.01, peter koch wrote: >> unless you intend to port very old code from Cobol or something similar. > Why? I guess it very much depends on your application area. > Personally, I have much use of strings with a static maximum size, using them whenever I program against an interface which defines maximum sizes for I/O. A static *maximum* size is helpful, indeed. But AFAICS the example always allocated the maximum size. This is big waste of memory unless the limit is only a few bytes. >> for read operations. >> Marcel > Certainly! Immutable and hopefully also constexpr so that I can manipulate them while compiling. Well, this is an even more advanced topic, since the restrictions for constexpr are quite tight. I don't think that a string class can have a /runtime/ dynamic length and constexpr (factory) functions at the same time, at least not with C++11. I had a similar requirement years ago. I.e. neither the string class constructors of program constants should invoke dynamic allocations at program startup, nor a dynamic allocation and string copying should happen every time the constant is accessed. In fact no copying of the constant data should be done at all. I ended up with a distinct class for this purpose. This one had the string length in the type and used the internal data structures of the 'normal' string class in a way that prevented the deallocator from running so it could bind to static storage rather than heap storage. It should be possible to write a class for your requirements that is compatible to the matching immutable string class. Marcel |
peter koch <peter.koch.larsen@gmail.com>: Jul 05 12:15PM -0700 Den onsdag den 5. juli 2017 kl. 20.46.28 UTC+2 skrev Marcel Mueller: > A static *maximum* size is helpful, indeed. > But AFAICS the example always allocated the maximum size. This is big > waste of memory unless the limit is only a few bytes. I do not know which example you are referring to. In my code, I simply choose between boost::container::static_vector and std::vector dependent on the maximum number of elements. When max_size < threshold/sizeof(T), I choose the static vector. threshold is currently defined as sizeof(std::string) and this seems like a reasonable default, assuming the compiler-folks have taken their time to decide on a proper size for SSO. For compile-time strings you want a newer compiler, at least C++14. And not Microsofts right now. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 05 01:40AM +0200 On 05-Jul-17 12:11 AM, Christiano wrote: > { > if (n==nullptr) return this; > if (this==nullptr) return n; Looks like a typo. It could be a thinko from habit, though, because when Bjarne designed the language it didn't have exceptions, so the way to signal construction failure was to do `this = 0;`. So at that time, before exceptions, the `this` pointer could certainly be 0. As I recall we got exception around 1989-1991, the time of the ARM. > paragraph 5.2.5/3 of the standard ISO/IEC 14882:2003(E)), calling any > nonstatic method of any class through a null-pointer leads to undefined > behavior. " Right. > But the ISO/IEC 14882:2003, § 5.2.5.3 says: If E1 has the type > "pointer to class X," then the expression E1->E2 is converted to the > equivalent form (*(E1)).E2; There is an infamous note (notes are non-normative in ISO standards) in C++14 §8.3.2/5 (or C++98 §8.3.2/4): "in particular, a null reference cannot exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by indirection through a null pointer, which causes undefined behavior" It's infamous because it /claims/ that the standard elsewhere prescribes UB for *p when p is a null pointer, but there is no such wording. Still, everyone agrees that it's UB to dereference a nullpointer, except in a `typeid` expression, where you're guaranteed an exception in that case. > of any class through a null-pointer leads to undefined behavior". > And (*(E1)) being a lvalue when E1 is null is not a problem IF THE > PROGRAMMER IS AWARE OF WHAT HE IS DOING. The compiler is free to insert code that checks for nullpointer and if so, plants some nasty NSA malware on your computer. > What I'm trying to say is exactly: > The "Comparing 'this' Pointer to Null as an undefined > behavior" is a MYTH which is not based on Standard. No, not a myth, but the standard has never been fixed. It /claims/, in non-normative text, that it says, but it doesn't actually say. That this state of affairs has lasted through three and now soon four revisions is pretty weird, but presumably more important stuff's been fixed instead. > You can see this myth in several websites: > https://www.google.com/#q=this+null+c%2B%2B > Following this reasoning, Stroustrup is correct, No, that code is just a typo or thinko. > g++ is correct [2], and Clang is correct [3]. Yes, UB means that they can do whatever. So I haven't even checked what you cite that they do. Or don't. > And the standard shouldn't forbid it because it has been used correctly > for a long time without problems so that it would be much fairer to be > interpreted as a technique. It was used for a long time – before C++ got exceptions. Which was roughly 10 years before the first standardization. [snip] Cheers & hth., - Alf |
Christiano <christiano@engineer.com>: Jul 04 10:24PM -0300 On 07/04/17 20:40, Alf P. Steinbach wrote: > Looks like a typo. > It could be a thinko from habit, though, because when Bjarne designed the language it didn't have exceptions, so the way to signal construction > failure was to do `this = 0;`. So at that time, before exceptions, the `this` pointer could certainly be 0. It was not that, because after he says: -------- excerpt begin --------- Note that this has a specific meaning: it points to the object for which a member function is called. It does not point to any old object. The compiler ensures that we do not change the value of this in a member function. For example: struct S { // . . . void mutate(S* p) { this = p; // error: this is immutable // . . . } }; ------------excerpt end ---------- The Link * that the function returns is the first link from a doubly linked-list (with Gods[1] inside). And if, for example: Link *p = nullptr; // EMPTY LIST p = p.insert(new Link{"Athena"}); // INSERTING ATHENA It will work just because insert return the new Athena making it as the new element of the list. I'm sure it was not a mistake. > exist in a well-defined program, because the only way to create such a reference would be to bind it to the "object" obtained by indirection through a > null pointer, which causes undefined behavior" >> It's infamous because it /claims/ that the standard elsewhere prescribes UB for *p when p is a null pointer, but there is no such wording. Exactly! There is no such wording. The difference here is: ✓ You and several peoples are saying that there should be such wording. ✓ I am saying that there should NOT be such wording. And this note should be corrected because it doesn't consider situations where the dereference doesn't access data and so shouldn't cause UB. The error here is to consider that all dereference implies data access. Obviously, if you do: int *a = nullptr; *a = 10; Of course, it is UB because the code above is obviously wrong. But the Stroustrup code, very interesting in my opinion, makes perfect sense. A specification fails to encompass all possibilities at first, the use of language showed that in this particular topic it has failed to foresee some possibilities, it is normal. So, in my opinion, it makes more sense to adapt the specification to reality than the reality to adapt to a possible and vague interpretation of the specification, which would invalid very interesting codes like that stroustrup's code. [1] Please, I am not promoting or disrespecting any religion, I am just following the example of the book which contain lists of ancient Greek and Nordic gods. |
Richard Damon <Richard@Damon-Family.org>: Jul 04 10:33PM -0400 On 7/4/17 6:11 PM, Christiano wrote: > of any class through a null-pointer leads to undefined behavior". > And (*(E1)) being a lvalue when E1 is null is not a problem IF THE > PROGRAMMER IS AWARE OF WHAT HE IS DOING. The problem is that the dereferencing of a null pointer is undefined behavior, so you haven't escaped the problem. Yes, sometimes if you know the implementation well enough, and are willing to take your chances it won't change, sometimes you can get away with undefined behavior. That doesn't make it reasonable to say the behavior shouldn't be undefined. Part of the issue with this is that the implementation can (and sometimes must) access hidden pieces of the object (like what is typically called the vtable) to work with an object, and the function might do so in its preamble as part of its standard operation (even if it later might see it doesn't need to). AFAIK, the only object that can't have this sort of data stored in them is what is called a POD (Plain Ole Data) which are layout compatible with C code. My memory is that early in the development of C++ there were cases where you could end up with a null this, but well before it came to the first standard this was dropped, |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 05 07:06AM +0200 On 05.07.17 03.24, Christiano wrote: > p = p.insert(new Link{"Athena"}); // INSERTING ATHENA > It will work just because insert return the new Athena making it as the > new element of the list. Invoking insert() on an object of type Link* won't compile. p = p->insert(new Link{"Athena"}); // INSERTING ATHENA might compile. But it is UB. The latter might also work es expected. UB always included the case that it works as expected. It is just not reliable. > ✓ I am saying that there should NOT be such wording. > And this note should be corrected because it doesn't consider situations > where the dereference doesn't access data and so shouldn't cause UB. This constraint is not sufficient. E.g. if in the above example insert is virtual it will crash. Even when the invoked method does not access any data. So it will basically only be valid for POD structures. But this prevents the constructor of Link to exist. > *a = 10; > Of course, it is UB because the code above is obviously wrong. But the > Stroustrup code, very interesting in my opinion, makes perfect sense. I have also written code which allows to invoke some simple functions on a null object in very rare cases. But this code was never intended to be portable. A specific platform might always give further guarantees, shrinking the area of UB. > more sense to adapt the specification to reality than the reality to > adapt to a possible and vague interpretation of the specification, which > would invalid very interesting codes like that stroustrup's code. Feel free to submit a draft. Marcel |
Christiano <christiano@engineer.com>: Jul 05 03:23AM -0300 On 07/05/17 02:06, Marcel Mueller wrote: > On 05.07.17 03.24, Christiano wrote: > Invoking insert() on an object of type Link* won't compile. Correcting: Link *p = nullptr; // EMPTY LIST p = p->insert(new Link{"Athena"}); // INSERTING ATHENA // p is pointing to Athena now. // p-->[athena] p = p->insert(new Link{"Odin"}); // INSERTING Odin // p is pointing to Odin now. // p-->[odin]<->[athena] > This constraint is not sufficient. > E.g. if in the above example insert is virtual it will crash. Even when the invoked method does not access any data. Yes, it will crash because virtual methods necessarily need to access data (virtual table) which compose the class object. But this case would be a wrong code. What is wrong with Stroustrup code? Nothing, because nonvirtual methods doesn't influence the object bytes. The Stroustrup's code is very interesting. Why it should be UB when it is not? You are talking about a different case, the Insert is not virtual therefore p->insert(new Link{"Athena"}); will not access any data from nullptr position (Insert will return on 2nd line). > So it will basically only be valid for POD structures. But this prevents the constructor of Link to exist. The stroustrup code works. The Link is defined as: class Link { public: string value; Link(const string& v, Link* p = nullptr, Link* s = nullptr) : value{v}, prev{p}, succ{s} { } Link* insert(Link* n) ; // insert n before this object Link* add(Link* n) ; // insert n after this object Link* erase() ; // remove this object from list Link* find(const string& s); // find s in list const Link* find(const string& s) const; // find s in const list (see §18.5.1) Link* advance(int n) const; // move n positions in list Link* next() const { return succ; } Link* previous() const { return prev; } private: Link* prev; Link* succ; }; It is not a POD. In C programming, it is common the following code: struct X *a = NULL; // ... a = (struct X *) malloc(N*sizeof(*a)); // EQUIVALENT: a = (struct X *) malloc(N*sizeof(struct X)); See: sizeof(*a) Does *a here cause UB? It will not cause UB... because sizeof(*a) actually doesn't need to access *a at all (it is a static operator). Now, see again: Link *p = nullptr; // EMPTY LIST p = p->insert(new Link{"Athena"}); // INSERTING ATHENA equivalent: p = (*p).insert(new Link{"Athena"}); The same thing: when compiler is generating code, this line actually doesn't need to generate code that access *p at all, p can be anything, In any architecture: MIPS, ARM, x86, Risc-V, SPARC, POWER, Microcontrollers whatever. In any Operating system: windows, macosx, linux, BSD, RTOS's whatever. Therefore comparing "this" with "nullptr" should be recognized as a technique. |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jul 05 05:12PM +0100 On 05/07/2017 07:23, Christiano wrote: > Therefore comparing "this" with "nullptr" should be recognized as a > technique. Wrong. Dereferencing a null pointer is UB so 'this' should never by null unless you are invoking UB. /Flibble |
peter koch <peter.koch.larsen@gmail.com>: Jul 05 10:59AM -0700 Den onsdag den 5. juli 2017 kl. 00.11.38 UTC+2 skrev Christiano: > n–>succ = this; // this object comes after n > if (prev) prev–>succ = n; > n–>prev = prev; // this object's predecessor becomes A conforming C++ compiler will know that this never can be null and will replace if (this == nullptr) with if (true). In fact clang gives this warning: <source>:6:13: warning: 'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to true [-Wtautological-undefined-compare] |
Marcel Mueller <news.5.maazl@spamgourmet.org>: Jul 05 08:19PM +0200 On 05.07.17 08.23, Christiano wrote: >> when the invoked method does not access any data. > Yes, it will crash because virtual methods necessarily need to access > data (virtual table) which compose the class object. The existence of the vtable pointer is already implementation defined. Although this is quite common. > p->insert(new Link{"Athena"}); > will not access any data from nullptr position (Insert will return on > 2nd line). Well, the standard simply does not require this kind of restriction for implementers. Implementations /might/ access the object behind *this of any non POD type for any implementation specific purpose. Not the functions are the problem, but the existence of a constructor makes the type non POD. And AFAIK even for POD types this == nullptr is not well defined behavior. Although it is likely to work since POD types should not contain any additional internal data members. On the other hand the code will also crash if inheritance comes into play. In case of multiple inheritance the raw pointer value has to be modified at explicit or implicit type conversions. This implies a nullptr-check unless the compiler is sure that the raw pointer cannot be nullptr. In fact the generated code for references and *this usually just adds a constant while for pointer types a conditional expression is generated. So in this case nullptr might be converted to some nonzero value and the this == nullptr check will fail. Again UB. >> So it will basically only be valid for POD structures. But this >> prevents the constructor of Link to exist. > The stroustrup code works. You can't tell this. It works on some platforms, maybe on many. But to tell that it always works (with a C++ compatible compiler) it must work on any platform, including the ones that do not yet exist. You can't prove that unless the code is standard conformant. > The Link is defined as: [...] > It is not a POD. Indeed. > See: sizeof(*a) > Does *a here cause UB? It will not cause UB... because sizeof(*a) > actually doesn't need to access *a at all (it is a static operator). Exactly. Neither sizeof nor typeof evaluate the expression. > p = (*p).insert(new Link{"Athena"}); > The same thing: when compiler is generating code, this line actually > doesn't need to generate code that access *p at all, p can be anything, The invocation of insert() /might/ access *p. > In any architecture: MIPS, ARM, x86, Risc-V, SPARC, POWER, > Microcontrollers whatever. In any Operating system: windows, macosx, > linux, BSD, RTOS's whatever. Well, making assumptions on platforms based on statistics is risky. E.g., I have worked on a platform where *(int*)0 might access a valid memory address (inmos T80x). > Therefore comparing "this" with "nullptr" should be recognized as a > technique. The standard might be enhanced in the way that this is well defined behavior for POD types. For now it is not. But I am in doubt that this will ever be defined for non POD types like the Link class above. Marcel |
legalize+jeeves@mail.xmission.com (Richard): Jul 05 06:02PM [Please do not mail me a copy of your followup] "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code >stdlib - UTF8 console i/o in Windows, other crucial fixes, functional >area headers Seems useful, but unfortunately a name like "stdlib" is a really poor name for this library IMO. It implies that this is somehow conencted with the C++ Standard Library, as opposed to a user written layer on top. Off the top of my head, names like "handylib", "alflib", or even "alfabits" (pun on US cereal name) would all be better names for this library. Actually, now that I'm seeing on screen, I like alfabits :). -- "The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline> The Terminals Wiki <http://terminals-wiki.org> The Computer Graphics Museum <http://computergraphicsmuseum.org> Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com> |
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