- C++ 17 in detail - Part 1 - Language Features - 11 Updates
- Run program and take first line from its stdout - 8 Updates
- More about arabs.. - 3 Updates
- Clever or tidy code snippets - 1 Update
Daniel <danielaparker@gmail.com>: Mar 09 06:24PM -0700 On Monday, March 9, 2020 at 6:45:37 PM UTC-4, Maciej Sobczak wrote: > > 1: Everyone agrees that it is impossible for a normal individual to > > understand all C++ > I have not seen any agreement on this (it's just your perspective). I would > rather say that it is not *necessary* for a normal individual to understand > all of C++. And nobody expects that. It's not so much that C++ has so many things, but rather, that it lacks all coherence, any vision, that it's one ad hoc thing after another. For what reason do we have std::string s = "foo"; const char* p = s.c_str(); // explicit, good but std::string_view sv = s; // implicit, bad for all the reasons we have c_str() and s = p; // Seems safe enough but s = std::string(sv); // Why? And collision between uniform initialization and initializer list. Why? The committee had to have known that, when they voted for it. And why introduce <system_error> requiring using _global objects_ for identifying error categories? Uniqueness of address doesn't work with DLL's, probably not shared libraries either, and the committee would have known that. The list is endless. Daniel |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 10 02:43AM +0100 On 10.03.2020 02:24, Daniel wrote: > const char* p = s.c_str(); // explicit, good > but > std::string_view sv = s; // implicit, bad for all the reasons we have c_str() For convenience when `std::string_view` is a formal argument type. This lets you define /one/ function, no overloads, that handles just about any non-zero-terminated string. > s = p; // Seems safe enough > but > s = std::string(sv); // Why? Yah. That one's ugly as heck. > And collision between uniform initialization and initializer list. Why? Agree about that also. It's botched. Bjarne's vision was nice, and I believe it was the committee that messed it totally up. > The committee had to have known that, when they voted for it. Politics I gather, combined with weak leadership. I think it's the same that happens in a lot of municipalities in Norway. The political leadership avoids taking on difficult issues. The bureaucrats then think that they just /have/ to make the decisions on behalf of the politicians, and they get away with it. However, a bureaucrat generally sees only his or her little very narrow and short slice of reality, and additionally, is often constrained by rules interpreted by the letter. Written rules don't have intelligence. The result is ungood. > identifying error categories? Uniqueness of address doesn't work with DLL's, > probably not shared libraries either, and the committee would have known that. > The list is endless. The lack of support for dynamic libraries is an open large wound in the language, so to speak. IMO. But which model to go for: Windows DLLs (very encapsulated), Linux shared libraries (like static libraries essentially, just dynamic), or maybe some third model defined by the committee, since there is strong precedence for not standardizing existing practice, but rather invent? Happily with C++20 there will be a `std::pi` (of course not the existing practice M_PI, from the Posix standard, but a pi value, hurray). And type safe text formatting based on format strings. They managed to dirty it by adding locale support. But I was wrong in thinking it was correct, as people had asserted, that they'd really sabotaged that library: by default locales aren't used, the use has to be requested, because the formatting is defined in terms of C++17 `std::to_chars`. So all's not lost. But the half-baked C++20 co-routines, which aren't really co-routines anyway but more like continuations, that's bad. And the fragile and inefficient ranges library, with its yet-another-domain-specific-sub-language-to-learn and `i(di)ota` func. Argh. - Alf |
Daniel <danielaparker@gmail.com>: Mar 09 08:11PM -0700 On Monday, March 9, 2020 at 9:43:50 PM UTC-4, Alf P. Steinbach wrote: >> known that. > The lack of support for dynamic libraries is an open large wound in the > language, so to speak. But that aside, why require equality of _addresses_? Equality of type_info doesn't require equality of addresses, only that they be the "same", my understanding is that MSVC satisfies that sameness requirement with string equality. So why require equality of addresses with error categories? I mean, the issue with uniqueness of address is understood, it's known. Daniel |
Daniel <danielaparker@gmail.com>: Mar 09 08:47PM -0700 On Monday, March 9, 2020 at 6:39:40 AM UTC-4, David Brown wrote: > C++ does suffer from a some serious issues, however. Backwards > compatibility can make things more awkward or bulky than it should be > (someone mentioned EBCDIC, for example). Coexisting with EBCDIC is only an issue because C++ lacks proper abstractions for byte sequences and text, and conversion utilities between them. In Java I can read any number of flavors of EBCDIC as bytes, convert those bytes into a unicode string, work with that string, and convert the result back to EBCDIC bytes. There's been prior art for that for a long long time, but C++ still doesn't have it. Daniel |
Ian Collins <ian-news@hotmail.com>: Mar 10 09:10PM +1300 On 10/03/2020 00:00, Bart wrote: >> ignoring) that. > Until you make a typo that would be thrown out by a C compiler, but is > legal in C++ and does something you don't expect. Which you are very unlikely to do. > Or if it is not legal in C++ either, it generates a 300-line error > message that you can't make head nor tail of. Which won't happen with C and a tiny bit more. You know that already, but like Jacob, you choose to ignore it. -- Ian. |
David Brown <david.brown@hesbynett.no>: Mar 10 11:11AM +0100 On 10/03/2020 09:10, Ian Collins wrote: >> message that you can't make head nor tail of. > Which won't happen with C and a tiny bit more. > You know that already, but like Jacob, you choose to ignore it. Just yesterday, I had a single typo that lead to hundreds of error messages in a different file - there was no indication of where the real error lay. That was a missing semicolon in a header - and it was all C, no C++ in sight. The idea that confusing or unhelpful error messages is purely a C++ phenomenon is just nonsense. C++ is a bigger language, and you can do a lot more in a few lines, so the scope for long error messages is greater. That just means you have to be a bit smarter, and use better tools, when working with it. A good IDE will help you navigate, and help you figure out which of the error messages are most relevant. And compilers have been getting better at this - gcc's error messages have become steadily more relevant, steadily better at pointing out what is /actually/ wrong, and steadily better at giving suggestions for corrections. Also, one of the motivations for newer C++ features like concepts and modules is to make it easier to find problems and simplify error messages. Concepts mean you'll get the messages when you define templates, rather than when you use them. |
David Brown <david.brown@hesbynett.no>: Mar 10 11:29AM +0100 On 10/03/2020 04:47, Daniel wrote: > string, and convert the result back to EBCDIC bytes. There's been > prior art for that for a long long time, but C++ still doesn't have > it. And the reason for that lack of abstraction is backwards compatibility, from C. That is not an excuse, of course - C++ should be working more towards a separation here (IMHO). There has been progress (std::byte, and char8_t are steps in the right direction). The trouble is, in order to do this properly, you'd need to break a good deal of code. In my ideal language, you'd have types: "char8_t" is a code unit for utf-8 data. It can hold any one ASCII character, and part of other utf-8 characters. Strings are stored in arrays of char8_t. "char32_t" is a code unit for utf-32 data. There is no "char", and certainly not the meaningless "signed char", "unsigned char" types, or the underspecified "wide char" junk. There is no utf-16 or UCS16 - these encodings sounded good on creation, but were dead-ends. (Of course you'd have libraries for importing and exporting utf-16 and other encodings, but they would not be fundamental types in the language.) There would be types "raw8_t", "raw16_t", etc. These are for untyped data sequences and low-level access. They would be allowed to alias any other types (like "unsigned char" today), and used for moving data around. There would be no arithmetic operations on them or comparisons other than == and !=. (It was a mistake to allow operations on std::byte.) You'd have signed and unsigned integer types of different sizes, but these would be entirely independent of the character types and raw types. How you could get there from today's C++ (assuming other people agreed with the aim!), I have no idea - it would involve massive changes and incompatibilities in existing code. |
Bart <bc@freeuk.com>: Mar 10 11:02AM On 10/03/2020 10:11, David Brown wrote: > error lay. That was a missing semicolon in a header - and it was all C, > no C++ in sight. The idea that confusing or unhelpful error messages is > purely a C++ phenomenon is just nonsense. But this is hundreds of different error messages, rather than hundreds of lines of the same message. The start point will be the first error message; no point in looking at the rest until the first has been dealt with. |
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Mar 10 12:30PM +0100 On 10.03.2020 04:11, Daniel wrote: > understanding is that MSVC satisfies that sameness requirement with string > equality. So why require equality of addresses with error categories? I mean, > the issue with uniqueness of address is understood, it's known. It /looks/ like `system_error` was lifted from the Boost library, where the address comparison was just a default for error categories that lacked id's, and that then for the standard library id's were removed. <url: https://www.boost.org/doc/libs/1_69_0/libs/system/doc/html/system.html#ref_nonvirtuals> Given the very Posix'y nature of `std::runtime_error` I'd guess the (assumed) id removal is just underhanded or even inadvertent Windows sabotage. For the "inadvertent" I guess the reasoning went like this: 1. BTW let's fix this, those random 64-bit compile time id's are kludges. Can we use more robust & safe 128-bit UUIDs? Maybe? 2. Hey, id's are not necessary, we can just use addresses. I tested this now [not mentioned: in Linux] and simply removed id's and it worked fine! 3. What a jolly good idea, a SIMPLIFICATION! Let's do that, yes. Same as changing the return type of `std::filesystem::path::u8string` in C++20 to incompatible: it's only a problem in Windows, not in *nix. - Alf |
David Brown <david.brown@hesbynett.no>: Mar 10 12:58PM +0100 On 10/03/2020 12:02, Bart wrote: >> purely a C++ phenomenon is just nonsense. > But this is hundreds of different error messages, rather than hundreds > of lines of the same message. Yes, the list I got had a large number of different error messages - and none of them were from the file with the actual typo. > The start point will be the first error message; no point in looking at > the rest until the first has been dealt with. Usually you can get a good idea by looking at the first and the last error message - that applies equally to C and C++. |
Daniel <danielaparker@gmail.com>: Mar 10 08:35AM -0700 On Tuesday, March 10, 2020 at 7:30:28 AM UTC-4, Alf P. Steinbach wrote: > lacked id's, and that then for the standard library id's were removed. > <url: > https://www.boost.org/doc/libs/1_69_0/libs/system/doc/html/system.html#ref_nonvirtuals> That was introduced into boost in 1_69_0, though boost 1_69_0: rhs.id_ == 0? this == &rhs: id_ == rhs.id_ boost 1_68_0: &lhs == &rhs; And from the release notes to 1_69_0: "error_category now has a constructor that accepts a 64 bit identifier, enabling distinct category objects to compare equal." The 64 bit identifier to be generated randomly by the implementor. Daniel |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Mar 10 06:55AM On Mon, 2020-03-09, Frederick Gotham wrote: > retrieve the first line of text from its stdout. If any kind of > error takes places, the function will simply return an empty > string. No exceptions will be thrown. ... > I will give a default timeout of 5 seconds for the second program to finish. Why? It's an unusual feature and complicates things. > #include <string> /* string */ > std::string Run_Command_string(std::string const &str_prog, > unsigned const timeout = 5u) noexcept Why not chrono here, so you don't have to wonder if it's 5 s or 5 ms? ... > std::getline(ip,retval); > /* Now just discard the rest of the output */ > for (string tmp; std::getline(ip,tmp); ) { /* Do Nothing */ } This means you're waiting for the whole input before you process the first line, and the whole input may be infinite, or take days to produce. The Unix way to handle this is (I think) to close the pipe and wait for the child to notice (via SIGPIPE at least) and die. I don't know what boost::process does to support it, or what would work on Windows. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 02:11AM -0700 On Tuesday, March 10, 2020 at 6:55:40 AM UTC, Jorgen Grahn wrote: > > I will give a default timeout of 5 seconds for the second program to finish. > Why? It's an unusual feature and complicates things. On one of the embedded-Linux devices I'm developing, you have to stop a system daemon before you can make a data request to the lens module. Sometimes it takes a few seconds for the daemon to stop, so I give it a maximum of 10 seconds before I consider it to have frozen or crashed. > > std::string Run_Command_string(std::string const &str_prog, > > unsigned const timeout = 5u) noexcept > Why not chrono here, so you don't have to wonder if it's 5 s or 5 ms? Yeah but wouldn't I need to turn it into a template function? Something like: template<class Rep, class Period> std::string Run_Command_string(std::string const &str_prog, std::chrono::duration<Rep,Period> const &timeout) noexcept > This means you're waiting for the whole input before you process the > first line, and the whole input may be infinite, or take days to > produce. That's why I've got the timeout. Actually now that I think of it, I could get the Reader thread to immediately notify the main thread when it's got the first line. |
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 05:28AM -0700 On Tuesday, March 10, 2020 at 6:55:40 AM UTC, Jorgen Grahn wrote: > This means you're waiting for the whole input before you process the > first line, and the whole input may be infinite, or take days to > produce. Here's my third attempt: /* The next function is to run a command and capture its first line of stdout. On failure, returns empty string. */ std::string Run_Command_string(std::string const &str_cmd, unsigned const timeout = 5u) noexcept { using std::string; namespace bp = boost::process; bp::ipstream *p_ip = nullptr; try { string retval; p_ip = new bp::ipstream; /* For capturing stdin from child process */ bp::child c(bp::search_path("sh"), "-c", str_cmd, bp::std_in.close(), bp::std_out > *p_ip, bp::std_err > bp::null); boost::mutex mutex_for_messaging; bool bHave_first_line_yet = false; boost::mutex::scoped_lock lock_for_condition(mutex_for_messaging); boost::condition_variable have_first_line_yet; //cout << "About to start Reader thread" << endl; /* Start second thread here to capture the first line of stdout */ boost::thread reader( [=, p_ip, &retval, &have_first_line_yet, &bHave_first_line_yet] { try { /* Retain the first line of text */ try { std::getline(*p_ip,retval); } catch (...) { retval.clear(); } bHave_first_line_yet = true; have_first_line_yet.notify_one(); /* The main thread is doing 'wait_for' */ /* ==== DANGER DANGER DANGER ==== Run_Command_string might have returned by this point ==== DANGER ==== DANGER */ /* so do not use retval, have_first_line_yet, bHave_first_line_yet past this point */ try { /* Now just discard the rest of the output */ for (string tmp; std::getline(*p_ip,tmp); ) { /* Do Nothing */ } } catch (...) { /* Do Nothing */ } delete p_ip; } catch (...) { /* Do Nothing */ } } ); bool const did_not_timeout = (boost::cv_status::no_timeout == have_first_line_yet.wait_for(lock_for_condition, boost::chrono::seconds(timeout))); if ( did_not_timeout && bHave_first_line_yet ) { /* We got the first line within the timeout! :-) */ reader.detach(); /* Allow it to continue reading lines from the child program */ //cout << "Finished in time: Reader thread" << endl; return retval; } else { //cout << "TIMEOUT: Reader thread" << endl; /* Program has frozen, so just return an empty string */ c.terminate(); reader.interrupt(); reader.detach(); } } catch (...) { /* Do Nothing */ } delete p_ip; /* Is there a chance that this could be a second deletion? */ return string(); } I have tested this on Linux with a sample program: void Do(void) { static std::mutex mtx; std::string const &retval1 = Run_Command_string("find / | grep bin"); mtx.lock(); cout << "==== ONE ==== " << retval1 << endl; mtx.unlock(); std::string const &retval2 = Run_Command_string("find / | grep usr"); mtx.lock(); cout << "==== TWO ==== " << retval2 << endl; mtx.unlock(); std::string const &retval3 = Run_Command_string("find / | grep lib"); mtx.lock(); cout << "==== TR3 ==== " << retval3 << endl; mtx.unlock(); } #include <vector> auto main(void) -> int { std::vector<std::thread*> vec; for (unsigned i = 0; i != 45; ++i) { vec.push_back(new std::thread(Do)); } for (;;) {} } Of course there's a few more things to take into account, such as whether the main thread should wait for all threads to finish (or to kill them) before returning from main. |
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 05:40AM -0700 On Tuesday, March 10, 2020 at 12:28:22 PM UTC, Frederick Gotham wrote: > delete p_ip; /* Is there a chance that this could be a second deletion? */ This definitely should be there. If it should be anywhere it should be right beside the call to thread::interrupt, but even then it isn't certain that the Reader thread hasn't already deleted it. |
cdalten@gmail.com: Mar 10 05:51AM -0700 On Tuesday, March 10, 2020 at 5:28:22 AM UTC-7, Frederick Gotham wrote: > for (;;) {} > } > Of course there's a few more things to take into account, such as whether the main thread should wait for all threads to finish (or to kill them) before returning from main. I think my IQ dropped 20 points after reading this crap. |
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 06:07AM -0700 > I think my IQ dropped 20 points after reading this crap. I know a guy who had his corpus callosum in his brain(s) severed so that he could think about two things independently at once without having one idea interfere with the other. (Effectively giving him two separate 'threads' of thought). I can't tell you more about him though because it's highly illegal to practise this surgery on people for experimental purposes (even if you are indeed a competent and fully-licensed medical surgeon). |
Frederick Gotham <cauldwell.thomas@gmail.com>: Mar 10 06:57AM -0700 On Tuesday, March 10, 2020 at 12:28:22 PM UTC, Frederick Gotham wrote: > Here's my third attempt: I might be going a little far with the static array of bits to keep track of deletions, but here's my fourth attempt: /* The next function is to run a command and capture its first line of stdout. On failure, returns empty string. */ std::string Run_Command_string(std::string const &str_cmd, unsigned const timeout = 5u) noexcept { /* ====== Determine all the limits and integer types in this block ======= */ typedef uint64_t IntBits; static std::size_t constexpr maxcalls = 1000000u; /* 1 million (must be divisable by width of IntBits) */ static uint_fast32_t counter = 0; /* 32-Bit can do up to 4 billion */ /* ================= END OF BLOCK ======================================== */ static std::size_t constexpr w = sizeof(IntBits) * CHAR_BIT; /* Assume no padding bits inside integer types */ static IntBits bits[maxcalls / w] = {}; /* Starts out all zero */ static boost::mutex mtx_bits; decltype(counter) local_counter; { /* This is a deliberate scope block */ boost::mutex::scoped_lock scpl(mtx_bits); local_counter = counter; bits[counter / w] |= static_cast<IntBits>(1) << (counter % w); ++counter; } using std::string; namespace bp = boost::process; bp::ipstream *p_ip = nullptr; try { string retval; p_ip = new bp::ipstream; /* For capturing stdin from child process */ bp::child c(bp::search_path("sh"), "-c", str_cmd, bp::std_in.close(), bp::std_out > *p_ip, bp::std_err > bp::null); boost::mutex mutex_for_messaging; bool bHave_first_line_yet = false; boost::mutex::scoped_lock lock_for_condition(mutex_for_messaging); boost::condition_variable have_first_line_yet; //cout << "About to start Reader thread" << endl; /* Start second thread here to capture the first line of stdout */ boost::thread reader( [=, p_ip, local_counter, &retval, &have_first_line_yet, &bHave_first_line_yet] { try { /* Retain the first line of text */ try { std::getline(*p_ip,retval); } catch (...) { retval.clear(); } bHave_first_line_yet = true; have_first_line_yet.notify_one(); /* The main thread is doing 'wait_for' */ /* ==== DANGER DANGER DANGER ==== Run_Command_string might have returned by this point ==== DANGER ==== DANGER */ /* so do not use retval, have_first_line_yet, bHave_first_line_yet past this point */ try { /* Now just discard the rest of the output */ for (string tmp; std::getline(*p_ip,tmp); ) { /* Do Nothing */ } } catch (...) { /* Do Nothing */ } { boost::mutex::scoped_lock scpl(mtx_bits); IntBits const mask = static_cast<IntBits>(1) << (local_counter % w); if ( bits[local_counter / w] & mask ) { delete p_ip; bits[local_counter / w] &= ~mask; } } } catch (...) { /* Do Nothing */ } } ); bool const did_not_timeout = (boost::cv_status::no_timeout == have_first_line_yet.wait_for(lock_for_condition, boost::chrono::seconds(timeout))); if ( did_not_timeout && bHave_first_line_yet ) { /* We got the first line within the timeout! :-) */ reader.detach(); /* Allow it to continue reading lines from the child program */ //cout << "Finished in time: Reader thread" << endl; return retval; } else { //cout << "TIMEOUT: Reader thread" << endl; /* Program has frozen, so just return an empty string */ c.terminate(); reader.interrupt(); reader.detach(); { /* This is a deliberate scope block */ boost::mutex::scoped_lock scpl(mtx_bits); IntBits const mask = static_cast<IntBits>(1) << (local_counter % w); if ( bits[local_counter / w] & mask ) { delete p_ip; bits[local_counter / w] &= ~mask; } } } } catch (...) { /* Do Nothing */ } return string(); } |
cdalten@gmail.com: Mar 10 07:07AM -0700 On Tuesday, March 10, 2020 at 6:57:28 AM UTC-7, Frederick Gotham wrote: > } > return string(); > } Not that I should encourage this shutout, but the following line that you commented out... //cout << "TIMEOUT: Reader thread" << endl; Is kind of incorrect because error messages on Linux are unbuffered. And again, you would have only known his had you taken my advice and read the book "Advanced Programming in the Unix Environment" by the late Dr. Stevens. And again, I think my IQ dropped 20 points after reading this crap. |
queequeg@trust.no1 (Queequeg): Mar 10 11:37AM > While there may be small differences between races these are dwarfed by > the differences within races. It's true, but I was refering to: "You honestly think that ethnicity and race are somehow linked to intelligence?" Studies show that, to some extent, it is. -- https://www.youtube.com/watch?v=9lSzL1DqQn0 |
Bo Persson <bo@bo-persson.se>: Mar 10 01:08PM +0100 On 2020-03-10 at 12:37, Queequeg wrote: > "You honestly think that ethnicity and race are somehow linked to > intelligence?" > Studies show that, to some extent, it is. No, the studies show that better education is well correlated to good results on IQ tests. If you, for example, were never taught how to read, you will score really badly. |
cdalten@gmail.com: Mar 10 05:46AM -0700 On Tuesday, March 10, 2020 at 5:08:37 AM UTC-7, Bo Persson wrote: > results on IQ tests. > If you, for example, were never taught how to read, you will score > really badly. Maybe. But I can think of one exception. One of histories greatest Mathematicians never really had an education. This was evident in his proof writing. Or lack thereof. But this guy, just like Euler, made significant contributions to almost every branch of Mathematics. According to one of the Professor's at Harvard who worked with him, at the age of 21, he was proving three theorems a day. |
"Öö Tiib" <ootiib@hot.ee>: Mar 10 01:06AM -0700 On Monday, 9 March 2020 11:54:32 UTC+2, David Brown wrote: > you'd dislike other rules too, and for equally good reasons.) Most > programmers work on the projects they are paid to work on and told to > work on, rather than projects they want to work on. I dislike deliberate usage of assignments in conditionals that are actually confusing ... like if(p=getP()). The if(getP()==p) or if(p==getP()) are both fine C++ for me. Probable typos in usage of operators = and == are diagnosed by majority of compilers and by lot of other tools. When reasonable proposals of discarding pointless rule and to set up tool-chain properly instead are rejected then it is not project for me. I am more profitable participant in other projects. Other people may be are different and that is normal. |
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