- "In defense of printf" - 11 Updates
- std::thread...too little, too late? - 9 Updates
Juha Nieminen <nospam@thanks.invalid>: Dec 18 08:33AM > less readable and more verbose output streams particularly > given the performance constraints on most of the C++ software > that I'm responsible for. C++ standard streams are less readable only if you really want to find the most complex case you can think of. In normal usage it's demonstrably even more readable. Either way, C++ streams are much more versatile, and I need to use them in actual projects (that I code as my payjob). I need them because typically I have several modules that all append output into a string, and those modules call further modules that append output into that string, and those further modules... and so on. std::printf() just doesn't allow me to do that. std::ostream does. Sure, you could probably create an implementation of a FILE structure that does that, but C++ streams already offer me that implementation readymade, so I can use it in any new program. Of course std::printf() is also unusable in templated code, while std::ostream is just fine (which comes handy when any of those modules I mention above is templated, and needs to output values of the template types to that string). --- news://freenews.netfront.net/ - complaints: news@netfront.net --- |
Ian Collins <ian-news@hotmail.com>: Dec 18 09:43PM +1300 Juha Nieminen wrote: > while std::ostream is just fine (which comes handy when any of > those modules I mention above is templated, and needs to output > values of the template types to that string). If you read any of his posts on this subject, you'll see he goes out of his way to ignore any mention of templates! -- Ian Collins |
Paavo Helde <myfirstname@osa.pri.ee>: Dec 18 02:56AM -0600 Juha Nieminen <nospam@thanks.invalid> wrote in news:m6u3ha$2tem$1 > because typically I have several modules that all append output > into a string, and those modules call further modules that append > output into that string, and those further modules... and so on. So, if you need appending to a string, why don't you use std::string::append()? Why streams? In my experience, a stream is much more complicated in such tasks because it might be bound to some non-standard locale which may create havoc with decimal points etc. Of course, printf() is even worse in this regard. > Of course std::printf() is also unusable in templated code, No, it's not. You just need to have a template or an overloaded function which converts needed things to strings: #include <boost/lexical_cast.hpp> #include <string> template<typename T> void ReportMismatch(T x, T y) { printf( "Received unexpected value (%s) instead of expected %s.\n", (boost::lexical_cast<std::string>(y)).c_str(), (boost::lexical_cast<std::string>(y)).c_str()); } (not that I am recommending this style, but it's clearly possible). Cheers Paavo |
jacob navia <jacob@spamsink.net>: Dec 18 06:01PM +0100 Le 17/12/2014 21:54, Jorgen Grahn a écrit : > [1] E.g. upthread, it looked like you still see operator<< () as > a bit-shift operator. Strange strange, when I compile this, it seems that g++ interprets << as a bit shift operator. Why is that then? /tmp $ cat ts.c int fn(int arg) { return arg << 3; } /tmp $ g++ -c ts.c /tmp $ |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Dec 18 08:17PM On Thu, 2014-12-18, jacob navia wrote: >> a bit-shift operator. > Strange strange, when I compile this, it seems that g++ interprets << as > a bit shift operator. Please /get over it/. We won, 20 years ago[1]. C++ has operator overloading, and operator<< () is not just for bit-shifting. /Jorgen [1] See "Design and evolution of C++", 1994. -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
Christopher Pisz <nospam@notanaddress.com>: Dec 18 02:45PM -0600 On 12/18/2014 2:17 PM, Jorgen Grahn wrote: > overloading, and operator<< () is not just for bit-shifting. > /Jorgen > [1] See "Design and evolution of C++", 1994. haha well said. |
Christian Gollwitzer <auriocus@gmx.de>: Dec 18 10:00PM +0100 Am 16.12.14 16:19, schrieb Scott Lurndal: > Of course, other opinions may differ. [sn/f]printf is far more readable, far more usable > and far more efficient than output streams. I like to quote this: http://www.adamlaiacano.com/post/22909357888/the-march-of-progress which makes the point. Please admire the first Java version! For some things, printf syntax is really hard to beat. boost::format is a modern take how it could look like in C++. Christian |
Dombo <dombo@disposable.invalid>: Dec 18 10:24PM +0100 Op 18-Dec-14 22:00, Christian Gollwitzer schreef: > which makes the point. Please admire the first Java version! For some > things, printf syntax is really hard to beat. boost::format is a modern > take how it could look like in C++. I find the syntax of boost::format rather awkward and non-intuitive, especially how arguments are passed and the use of % to separate the arguments. I haven't used it myself yet, but the C++ Format library (https://github.com/cppformat/cppformat) looks like a interesting alternative. It seems to be the best of both worlds; familiar syntax, type safe, extendable and if the benchmarks on its webpage are to be believed it also performs much better than boost::format and iostream. |
Vir Campestris <vir.campestris@invalid.invalid>: Dec 18 09:32PM On 16/12/2014 21:28, Scott Lurndal wrote: > more efficient or more readable than: > printf("0x%x\n", x); > ? I prefer printf. But ITYM printf("0x%08x\n", x); Andy |
jacob navia <jacob@spamsink.net>: Dec 18 10:59PM +0100 Le 18/12/2014 21:17, Jorgen Grahn a écrit : > C++ has operator overloading, Yes! Obviously "overloading" means adding a new meaning to an operator that is already defined. The old meaning stays. The new one should be near the meaning that the operator had... at least what reading it is concerned. You can "overload" an operator like "+" to add a new kind of numbers, for instance. Very good. But overloading "+" to mean "Add this record to the database without error reporting" is not very intuitive! Why <<? Bit shifting is not really near output to a stream... And then, all the formatting instructions must be squeezed into this paradigm, intermixing into the flow width settings, precision settings, etc, what makes for a very verbose stuff. This original design error is what makes the whole unbearable. printf is a run time interpreter of format strings and an argument stream. It could be simplified if we would add a new %! for instance, that would match the default format for the corresponding argument. printf("%! %! %!\n", 56,7344.76,"foo"); would be equivalent to: printf("%d %g %s\n",56,7344.76,"foo"); the correct format supplied by the compiler at compile time. A class would need to define its own default format to have the same type safety of the cout<< constructs. Ypu could do MyClass m; printf("%!",m); And the default formatting function would be called to return a string. The constructor of the string would receive as (optional) arguments a width and a precision and some flags if present in the printf specification string. A kind of C++ printf. |
Christopher Pisz <nospam@notanaddress.com>: Dec 18 05:31PM -0600 On 12/18/2014 3:59 PM, jacob navia wrote: > paradigm, intermixing into the flow width settings, precision settings, > etc, what makes for a very verbose stuff. > This original design error is what makes the whole unbearable. I suppose you can't tell the difference between int myValue = *iterator int myValue = 4 * myNumber; I mean who decided to use * for two completely different things?! *sarcasm* > The constructor of the string would receive as (optional) arguments a > width and a precision and some flags if present in the printf > specification string. A kind of C++ printf. Look man, I simply don't want to refer to a page of more than 80 type characters, width specifiers, precision specifications, prefixes, or suffixes to read one line of code. Having to memorize tables of codes to get anything done is the C way. I leave my decoder rings in the box of cereal. For those that already memorized the damn thing in 1970 and even its least used parts, good for you. I have the same respect for you as I do the guy who had to do calculus without a calculator, but I will bring my calculator when I need to do a calculus problem. |
me <noone@all.net>: Dec 18 11:36AM I was looking at what made its way into the C++11 standard in the way of threads, and it seems very braindead. I mean third party libraries have been giving us working threading for years, and "THAT"was all they came up with for the standard? I fully understand the implications of adding features that need to be portable and that give a good least common denominator, but std::thread seems too little, too late. I thought it would be easy to at least build upon the std::thread class and to something that more closely resembles the common threading utility available in a variety of libraries: something with delayed thread starting, and the ability to make the process OO with a virtual run() method...no such luck. Consider the following example that uses std::thread as a class trait and then subclasses a UsefulThread class, adding the requested functionality: class UsefulThread { thread* stdThread; public: UsefulThread(); virtual ~UsefulThread() { delete stdThread; } virtual void run()=0; void start() { stdThread=new thread(run); } void join() { stdThread->join(); } }; class WorkerThread: public UsefulThread { int _id; BufferObject& r; public: WorkerThread(int id, BufferObject& b): UsefulThread(), _id(id), r(b) {} virtual void run() { for (auto i=0; i<_id; i++) r << _id; } // share r object is made threadsafe with an internal mutex }; int main(int argc, char** argv) { using namespace std; list<int> v ={1, 2, 3, 4, 5, 6, 7, 8, 9}; BufferObject b; list<WorkerThread> threadList; for (auto i: v) { WorkerThread t(i, b); threadList.push_back(t); }; for (auto i: threadList) i.start(); for (auto i: threadList) i.join(); cout << b.str() << endl; return 0; } There is no way (that I can tell of) to make the UsefulThread::start() method properly register the run() virtual. There was an article online at <http://rafalcieslak.wordpress.com/2014/05/16/c11-stdthreads-managed- by-a-designated-class/> where the author tries to address the delayed start issue. Problem is that 1) he doesn't allow for a virtual run() method, and 2) when using a normal thread object instead of a thread* the resulting WorkerThread cannot be put into any sort of std container, and gives compile errors about (use of deleted function) from the constructor. |
"Öö Tiib" <ootiib@hot.ee>: Dec 18 09:39AM -0800 On Thursday, 18 December 2014 13:36:11 UTC+2, me wrote: > I was looking at what made its way into the C++11 standard in the way of > threads, and it seems very braindead. Hey, brain-alive, where were you, what woke you up?! 2014 is ending soon. std::thread is mostly based on Boost.Thread that has been around since 2001. |
Christopher Pisz <nospam@notanaddress.com>: Dec 18 01:21PM -0600 On 12/18/2014 5:36 AM, me wrote: > method, and 2) when using a normal thread object instead of a thread* the > resulting WorkerThread cannot be put into any sort of std container, and > gives compile errors about (use of deleted function) from the constructor. I am not sure what the beef is. Are you trying to make a virtual Run method that derived classes can implement, but can't? I am sure I've successfully done that in the past as well as maintain a pool of threads in a base class via boost thread, so I don't see why it would be a problem with std::thread which came from boost thread. |
Paavo Helde <myfirstname@osa.pri.ee>: Dec 18 01:35PM -0600 > cout << b.str() << endl; > return 0; > } This example mostly demonstrates antipatterns and is probably inspired by some Java-originating ideas that everything must be OO and derived from some common base class. I have not used std::thread but I gather it is similar to boost::thread so I use that instead as a reference. The data in the WorkerThread object remains in shared use so the access to it must be protected. With boost::thread the functor object will be copied over to another thread before the actual thread start, ensuring that the user does not have to worry about how to get the data safely into the new thread. The delayed start() method complicates the usage and implementation and is not needed for anything. If the thread needs to wait before performing any actual tasks it could just wait on some condition in the start of the thread function. The run() function is called only once when the thread is created. At the thread creation time the exact class which is created is of course known so there is no need to have run() as a virtual function. In the above example it is virtual only because somebody wanted to call it from a useless non-template base class. > the resulting WorkerThread cannot be put into any sort of std > container, and gives compile errors about (use of deleted function) > from the constructor. This is because copying of threads does not make sense (should it spawn a new thread or what?), and all STL containers are based on value copying. Use some pointers or smartpointers instead for holding the thread objects in a container. So the idea behind boost::thread and std::thread is to provide the most simple building block, without any unnecessary kludges like forcing use of virtual functions and without forcing use of shared data. It can be used quite easily in simple scenarios. If a more complex scenario is needed, one can build on top of it (like WorkerThread does, albeit in ill fashion). For example, to avoid functor copying and keep data in shared use one can define a simple template (probably boost has it already defined by some other name) which can be used for all such threads: template<typename T> struct FunctorForwarder { T& p_; FunctorForwarder(T& p): p_(p) {} void operator()() {p_();} }; class TimerMgr { public: TimerMgr(): thread_(FunctorForwarder<TimerMgr>(*this)) {} void operator()() { // the thread function } // ... private: boost::thread thread_; // ... shared data }; hth Paavo |
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Dec 18 09:05PM On 18/12/2014 11:36, me wrote: > } > There is no way (that I can tell of) to make the UsefulThread::start() > method properly register the run() virtual. There was an article online Stop fucking moaning mate. void start() { stdThread=new thread(std::bind(&UsefulThread::run, this)); } /Flibble |
me <noone@all.net>: Dec 18 10:11PM On Thu, 18 Dec 2014 09:39:17 -0800, Öö Tiib wrote: > Hey, brain-alive, where were you, what woke you up?! 2014 is ending > soon. std::thread is mostly based on Boost.Thread that has been around > since 2001. Well, here's you're answer. I've religiously stayed away from anything boost. The times I've had to use it I encountered poor documentation and too frequently changing interface semantics. Other third party platforms accomplished more with less effort. commoncpp and trolltech-qt had much better features. Just thought I'd take a look at the c++11 std to see what made its way in and got a good chuckle over it. Asbestos firesuit is now on. Flame at will! LOL |
Christopher Pisz <nospam@notanaddress.com>: Dec 18 04:47PM -0600 On 12/18/2014 4:11 PM, me wrote: > boost. The times I've had to use it I encountered poor documentation and > too frequently changing interface semantics. Other third party platforms > accomplished more with less effort. Oh....oh my...what in the world? |
me <noone@all.net>: Dec 18 10:48PM On Thu, 18 Dec 2014 11:36:01 +0000, me wrote: > the resulting WorkerThread cannot be put into any sort of std container, > and gives compile errors about (use of deleted function) from the > constructor. Problem solved via a work-around. Doesn't seem to be a valid way to make std::thread(v) recognize v when it is a pure virtual, implemented in a subclass. The work-around is to register a stub-function and have that function call the virtual...and the non-copyable nature of std::thread also causes me grief (particularly in managing lists of threads or thread pools). I understand the "why" but that doesn't mean I have to like it or a gree with it. |
legalize+jeeves@mail.xmission.com (Richard): Dec 18 11:20PM [Please do not mail me a copy of your followup] me <noone@all.net> spake the secret code >Well, here's you're answer. I've religiously stayed away from anything >boost. That's certainly your choice, but you're really missing out on the single most important community that is influencing the future of C++. -- "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> |
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