• (cs)

    TRWTF is pointers.

  • rjb (unregistered)

    I'm not going to lie, though I'd never append a null to the end of a string just for shits and giggles, programming in C++, especially with third party libraries, is often an exercise in frustration with regard to pointers, and the path of least resistance is to just try each pointer/object operator and go with whatever compiles properly.

  • Sebastian Buchannon (unregistered) in reply to Severity One
    Severity One:
    TRWTF is pointers.

    actually no

  • ipeet (unregistered)

    Something is fishy here. That code wouldn't make it past the type checker.

  • DonaldK (unregistered)

    So what's the problem then?

    ;-)

  • TheSHEEEP (unregistered) in reply to ipeet
    ipeet:
    Something is fishy here. That code wouldn't make it past the type checker.

    Disabled warnings. :D

  • Cbuttius (unregistered)

    That code is valid C++ assuming that Buffer is a member variable of type char *.

    The real WTF is that they are implementing their own string class, albeit that what they are trying to do there is not possible with std::string which has no function to return you a writable buffer.

    However that is still a WTF as they should at least interpret it internally as a std::vector<char>

    The +'\0' is stupid, of course but the compiler probably just strips it out.

    Of course it will not put a null terminator on the end of your array. Doing so would be wrong anyway. What would happen if you call this multiple times?

  • Cbuttius (unregistered) in reply to TheSHEEEP
    TheSHEEEP:
    ipeet:
    Something is fishy here. That code wouldn't make it past the type checker.

    Disabled warnings. :D

    You probably won't get a warning here though. You normally get a "possible loss of data" when converting from a larger integral type to a smaller one but converting from char to int does not risk any loss of data.

  • Is a good name (unregistered)

    Depending on how -> and + are overloaded, this might indeed do exactly what the programmer intended to do...

  • mb (unregistered) in reply to rjb
    rjb:
    I'm not going to lie, though I'd never append a null to the end of a string just for shits and giggles, programming in C++, especially with third party libraries, is often an exercise in frustration with regard to pointers, and the path of least resistance is to just try each pointer/object operator and go with whatever compiles properly.

    Seriously? I always thought that C++ is precisely the type of language where you can shoot your self in the foot spectacularly with such attitude. I mean like

    bool * myBool = new bool;
    *myBool = true;
    if (myBool) {
      printf("It works, hence the condition on the line above is obviously correct!");
    }
    
  • beendoingthistoolong (unregistered)

    TRWTF is returning char* not const char*, right?

    It seems an odd representative line to me. The compiler almost certainly just drops the +0 operation as redundant and it all works fine. Yes, the author clearly didn't get it, but this is pretty common with part-time or new c++'ers.

    Operator overloading is pretty evil in general, but this would have been more useful generally with:

    const char * String::operator const char *() { return buffer; }

    (or even char *)

  • (cs) in reply to beendoingthistoolong
    beendoingthistoolong:
    TRWTF is returning char* not const char*, right?

    It seems an odd representative line to me. The compiler almost certainly just drops the +0 operation as redundant and it all works fine. Yes, the author clearly didn't get it, but this is pretty common with part-time or new c++'ers.

    Operator overloading is pretty evil in general, but this would have been more useful generally with:

    const char * String::operator const char *() { return buffer; }

    (or even char *)

    Actually...

    #if __cplusplus >= 201103L
    #define EXPLICIT explicit
    #else
    #define EXPLICIT
    #endif
    
    EXPLICIT String::operator const char*() const {
        return buffer;
    }
    
  • Cbuttius (unregistered)
    class String
    {
    private:
    
       class Impl
       {
          mutable vector< char > buf;
          public:
          char * operator+( char ch ) const
          {
              buf.push_back( ch );
              return &buf[0];
          }
       };
    
       Impl Buffer; 
    };
    
  • (cs)

    I love pointers so much! And strings!

    But indeed, when you don't master it, it can lead to big WTF!! Like this one... Or like some in the code I have to maintain...

  • History Teacher (unregistered) in reply to Severity One
    Severity One:
    TRWTF is pointers.
    ...are you the author of this particular representative line, by any chance?

    TRWTF are coders who don't understand pointers, yet touch any language less separated from hardware than crossplatform HTML+javascript.

  • (cs) in reply to History Teacher
    History Teacher:
    Severity One:
    TRWTF is pointers.
    ...are you the author of this particular representative line, by any chance?
    No.
    History Teacher:
    TRWTF are coders who don't understand pointers, yet touch any language less separated from hardware than crossplatform HTML+javascript.
    Oh, I understand pointers, but they are too easy to muck up, especially with C++'s Byzantine syntax, and an object-oriented language offers enough tools to pretend that pointers do not exist (such as Java does). Unless you're doing serious low-level or high-performance computing, there isn't much use for pointers.
  • (cs)

    Seeing that attempt at "string concatenation" leaves me with the feeling that Benedikt's predecessor may have been a Java programmer.

    Of course, TRWTF is C++. It could have been an elegant and simple object oriented superset of C, but instead it's a glorious example of how not to design a programming language. In fact, I'm not entirely sure this is a joke:

    http://www-users.cs.york.ac.uk/~susan/joke/cpp.htm

    The other RWTF is Akismet

  • Dave-Sir (unregistered) in reply to Cbuttius
    Cbuttius:
    TheSHEEEP:
    ipeet:
    Something is fishy here. That code wouldn't make it past the type checker.

    Disabled warnings. :D

    You probably won't get a warning here though. You normally get a "possible loss of data" when converting from a larger integral type to a smaller one but converting from char to int does not risk any loss of data.

    You won't get any warning, but not for the reasons you state.

    The type of '\0' is int. Assuming buffer is a pointer to char, adding an int to a pointer is a perfectly valid operation, and not worthy of a warning.

    It reminds me of some code I encountered some years ago. To test fo an odd number, the following code was used:

    if (value&1 == 1) <etc.>

    However, because of precedence rules, this gets parsed as

    if (value & (1==1))

    But it still works. Just not the way the original programmer thought.

  • RandomUser423718 (unregistered) in reply to Severity One
    Severity One:
    Oh, I understand pointers, but they are too easy to muck up, especially with C++'s Byzantine syntax, and an object-oriented language offers enough tools to pretend that pointers do not exist (such as Java does). Unless you're doing serious low-level or high-performance computing, there isn't much use for pointers.
    BOCTAOE

    When referring to "physical memory" pointers, maybe. However pointers, as a concept, are important for understanding any number of common patterns, such at those that appear in relational databases (primary/foreign keys), etc.

  • Cbuttius (unregistered)

    Calling a pointer a reference doesn't mean it is not a pointer.

    Java has pointers. They call them references and use . syntax instead of -> but they have the semantics of pointers.

    You don't have to delete them because Java has automated garbage collection.

    That is why if you don't assign one to anything then try to use it you get a NullPointerException.

    Remember that C++ was originally a layer on top of C that brought in some concepts from other OO languages that were there at the time, and one of the main important things supported is RAII which essentially means cleaning up through objects' automatic destructors.

    That is why, if you use the string class, you don't have to mess about with pointers.

    But yes, you can integrate with C easily which means if there is a library in C you can just use it. So sometimes you need to get a C string out of your "managed" classes. If you want a contiguous writable buffer you should use vector<char> underneath, not std::string. The overload of operator+ in my example was a bit of a joke though. If you are going to give it operator+ it should have the proper semantics of that operator so.

    String operator+( String const& s, char ch )
    {
       String s2( s );
       s2.append(ch); # or push_back or +=
       return s2; 
    }
    

    Yes, operator+ returns a new object and leaves the old object in an unchanged state.

    As long as you obey the spirit of the rules of operators when you overload them, users of your class won't get into trouble. It is true that doing the above a lot will be inefficient but then you won't be doing that as to build strings you use ostringstream.

  • Jack (unregistered) in reply to Dave-Sir
    Dave-Sir:
    However, because of precedence rules
    Precedence? WTF is precedence? That looks like a Very Big Word. I should not have to know it. I should not have to know anything. The computer should just do what I want.

    Programming languages are TRWTF. Nobody wants to type commands. So boring. And hard, dammit! There should just be a big round candy colored button and when I click it, it reads my mind and Just Works. If you can't design something to cater to my fantasy, you are no good.

  • rjb (unregistered) in reply to mb

    Perhaps I misworded what I said. What I meant was compiles properly, and exhibits the desired behavior. If it doesn't exhibit the desired behavior, then I wouldn't say it compiled properly, it just compiled. :p

  • ¯\(°_o)/¯ I DUNNO LOL (unregistered) in reply to DonaldK
    DonaldK:
    So what's the problem then?
    Rolling your own String class?

    Oh wait, I know... it needs a regex!

    Actually, TRWTF is operator overloading.

  • (cs) in reply to java.lang.Chris;
    java.lang.Chris;:
    Seeing that attempt at "string concatenation" leaves me with the feeling that Benedikt's predecessor may have been a Java programmer.
    As opposed to a colleague of mine at a previous job of mine, who had been doing too much work with JavaScript.

    So, to present a message like "Elements found: {number}", he would exploit JavaScript's unnatural fascination with automatic type conversions:

      var value = calculationFunction( parameters );
      var message = "Elements found: " + value;

    This doesn't work so well in C++.

  • Ross (unregistered)

    This code is painful to look at on so many levels. TRWTF is that, given the pointer from this function, the calling code can mess with the data in the object without, presumably, any data length or integrity checking.

    Encapsulation? We don't need no stinkin' encapsulation!

  • (cs)

    Heh. It's so rare for us to see C++ WTFs on this site that when one is finally posted, most of the comments focus on generalities about the language itself.

  • Ross (unregistered) in reply to java.lang.Chris;

    I love Stroustrup's quote:

    "There are only two kinds of languages: the ones people complain about and the ones nobody uses."

  • (cs) in reply to Steve The Cynic
    Steve The Cynic:
    As opposed to a colleague of mine at a previous job of mine, who had been doing too much work with JavaScript.

    So, to present a message like "Elements found: {number}", he would exploit JavaScript's unnatural fascination with automatic type conversions:

      var value = calculationFunction( parameters );
      var message = "Elements found: " + value;

    This doesn't work so well in C++.

    Sadly, there's a lot of odd code that a C++ compiler will happily compile:

    [chris@titwank ~]$ cat ouch.cpp 
    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int
    main()
    {
        string s = "Are we having fun yet?";
        int value = 0xdeadbeef;
        cout << s.c_str() + value << endl;
        return 0;
    }
    [chris@titwank ~]$ c++ -o ouch ouch.cpp 
    [chris@titwank ~]$ ./ouch 
    Segmentation fault (core dumped)
    
  • Bartholemew Taps (unregistered)

    This one brings to mind adages such as "there's never time to do it right but there's always time to do it over", or more succinctly "measure once cut twice; measure twice cut once".

    The problem is that people get nervous about the idea of trying to do something properly (in this case checking the types). But the prospect of guessing and hoping seems less nervous.

    It seems back-to-front, but it's not surprising if you follow a rule of higher risk -> lower outlay. Since writing software seems risky to such people, they minimise their outlay i.e. the amount of time they spend on the first coded version.

    Of course, experience of doing it the "right way" would help them realise that they can drive down the risk by using good processes.

  • Cbuttius (unregistered)

    Using the null character to denote end of string has its advantages but can be a WTF at times.

    Prefixing the length means it is faster to calculate the length of the string but makes it less maintainable. Firstly the potential length of the string is limited by the length of its header, and secondly when you modify the string you have to modify this length.

    In addition, there is the method of "tokenising" a string that into lots of strings by modifying the "separator" character into a null, allowing each component to be a string on its own. In fact sometimes you use a double zero to indicate the end of the sequence.

    Of course for binary "blobs" there will often be embedded null characters but in general these are not modified or lengthened the same way strings often are.

    The real WTF with C++ and strings is that the standard string is:

    1. really a typedef of template basic_string<char, char_traits<char>, allocator<char> >
    2. No standard ABI so if your library uses std::string in its interface it isn't guaranteed to work with a different library that uses a different compiler.

    It wasn't that long ago that you couldn't even pass a std::string between DLLs / shared objects built with the same compiler.

    All of which leads to you finding lots of "own implementations" of string, especially in legacy code.

    Of course, legacy code is still around because people still use these projects that are being maintained and they brought in enough money to the business.

  • (cs)

    I'm surprised no one said:

    "First\0"

  • (cs) in reply to java.lang.Chris;
    java.lang.Chris;:
    Seeing that attempt at "string concatenation" leaves me with the feeling that Benedikt's predecessor may have been a Java programmer.

    Of course, TRWTF is C++. It could have been an elegant and simple object oriented superset of C, but instead it's a glorious example of how not to design a programming language.

    That's been tried. It's called Objective-C, and it's such a smelly pile of WTF that no one uses it unless Apple is stuffing it down their throats.

    Is it even possible to create an elegant and simple superset of something that it itself neither elegant nor simple? C++ may be a glorious example of how not to design a programming language, but it got half of its mess from C and most of the other half is hacks to try to make it possible for higher-level concepts to integrate properly onto the existing C foundation.

  • (cs)

    TRWTF is rolling out their own string implementation.

    You know, as if C++ doesn't have enough of these already.

  • Cbuttius (unregistered) in reply to ericmorton
    ericmorton:
    I'm surprised no one said:

    "First\0"

    Because in C++ you start counting from 0.

    So the first post should read:

    0th...

  • Asdlarfgs (unregistered) in reply to Steve The Cynic
    Steve The Cynic:
    So, to present a message like "Elements found: {number}", he would exploit JavaScript's unnatural fascination with automatic type conversions:
      var value = calculationFunction( parameters );
      var message = "Elements found: " + value;
    How... how is that "exploiting JavaScript's unnatural fascination with automatic type conversions"? That's just the natural way to do it in most dynamic languages.
  • Cbuttius (unregistered) in reply to lucidfox
    lucidfox:
    TRWTF is rolling out their own string implementation.

    You know, as if C++ doesn't have enough of these already.

    It depends if they actually do need to get a char * out of it (rather than a const char *) in which case you can't do it with std::string.

    But in this case your implementation should use std::vector<char> underneath and not raw pointers.

    However if you handle a lot of very short strings, there is an advantage in using a "local" member class buffer to handle short strings rather than allocate as allocations are expensive. In such a case you will probably have a member function to get the data buffer.

  • Dan (unregistered) in reply to Bartholemew Taps
    Bartholemew Taps:
    measure once cut twice; measure twice cut once
    I hired a contractor to do some remodeling and learned, to my great dismay, chagrin, and expense, that his philosophy was "measure zero, cut three times".

    He actually installed a door frame, forgot to account for the thickness of sheetrock, tore it out, installed it again a half inch down, realized he forgot to account for the trim, tore it out again, installed it again, and it was still wrong. I forget why this time.

    I wanted to fire him but he had me by the balls. That part, he was really good at.

    Years later, I still curse his memory every time I walk down my crooked hallway. He also left me with a ceiling that slopes, and a roof that doesn't. All because he was fundamentally averse to a measuring tape and simple addition.

    Remodeling is hell. Stay as far away as you can.

  • iToad (unregistered)

    It would be amusing to run the source code through PC-lint, and see just how many other issues like this are lurking deep in the code.

  • Stev (unregistered)

    TRWTF is people complaining that a language "lets you shoot yourself in the foot". A gun will let you shoot yourself in the foot, much like a hammer will let you smash your thumb and a saw will let you cut your fingers off. C++ is a tool like any other and will cause a bloody mess if used without proper training or care, or if used in an inappropriate situation.

    You wouldn't use a chainsaw to slice a lemon in a cramped kitchen, nor would you use a carving knife to cut down a tree. C++ is no different - it has its place and where it is used appropriately it is positively unmatched. Likewise, when used inappropriately it'll cause massive amounts of bloodshed.

    The same can be said for just about any language. Deal with it.

  • (cs) in reply to Mason Wheeler
    Mason Wheeler:
    java.lang.Chris;:
    Of course, TRWTF is C++. It could have been an elegant and simple object oriented superset of C, but instead it's a glorious example of how not to design a programming language.

    That's been tried. It's called Objective-C, and it's such a smelly pile of WTF that no one uses it unless Apple is stuffing it down their throats.

    I actually like Objective-C, since it essentially combines my two favourite programming languages - Smalltalk and C. Compared to C++ it feels much more intuitive once you get past the culture shock of seeing so many square brackets.

    Mason Wheeler:
    Is it even possible to create an elegant and simple superset of something that it itself neither elegant nor simple? C++ may be a glorious example of how not to design a programming language, but it got half of its mess from C and most of the other half is hacks to try to make it possible for higher-level concepts to integrate properly onto the existing C foundation.

    I'd argue that C++ is largely a WTF of it's own making, since it's not a strict superset of C so it can't really blame it's forebear, and got a lot of things wrong in the object model and the standard library. I'd have preferred virtual methods by default, and for dubious "experiments" such as vectors of bools to have not made it into the standard. That's just scratching the surface - for more WTF'ery, refer to the Exceptional C++ and Effective C++ books.

  • iWantToKeepAnon (unregistered)

    Buffer could very well be a class that has overloaded the plus operator. The real WTF is operator overloading so that you can never really know what is going on.

    This is just more postings by code snobs. Come on, let's get back to the really gross stuff and stop complaining about people's syntax. :-[

  • (cs) in reply to rjb
    rjb:
    the path of least resistance is to just try each pointer/object operator and go with whatever compiles properly.
    Some of us can think faster than the code compiles.
  • jMerliN (unregistered) in reply to Is a good name
    Is a good name:
    Depending on how -> and + are overloaded, this might indeed do exactly what the programmer intended to do...

    TRWTF is operator overloading. When the language constructs are user-defined, everything is WTF.

  • n_slash_a (unregistered) in reply to Stev
    Stev:
    TRWTF is people complaining that a language "lets you shoot yourself in the foot". A gun will let you shoot yourself in the foot, much like a hammer will let you smash your thumb and a saw will let you cut your fingers off. C++ is a tool like any other and will cause a bloody mess if used without proper training or care, or if used in an inappropriate situation.

    You wouldn't use a chainsaw to slice a lemon in a cramped kitchen, nor would you use a carving knife to cut down a tree. C++ is no different - it has its place and where it is used appropriately it is positively unmatched. Likewise, when used inappropriately it'll cause massive amounts of bloodshed.

    The same can be said for just about any language. Deal with it.

    Well stated. This is why a good company (should) hire engineers and not half-trained monkeys.

  • (cs) in reply to Ross
    Ross:
    I love Stroustrup's quote:

    "There are only two kinds of languages: the ones people complain about and the ones nobody uses."

    We need a 'like' or thumbs up button in here

  • (cs) in reply to jMerliN
    jMerliN:
    Is a good name:
    Depending on how -> and + are overloaded, this might indeed do exactly what the programmer intended to do...

    TRWTF is operator overloading. When the language constructs are user-defined, everything is WTF.

    I disagree. There are plenty of useful things you can do with operater overloading. Performing math on data types so you can add matrices together with operaters. Its up to the programmer to be smart about it and implement it in a sensible way (and document it)

  • danbruc (unregistered) in reply to Cbuttius
    Cbuttius:
    Calling a pointer a reference doesn't mean it is not a pointer.
    That's not true. In C# there is a single thing you can do with a reference - dereference it. A reference is either a null reference or a reference to an object of its specific type. You are neither allowed to use pointer math to point to the interior of an object or to random garbage in memory, nor are you allowed to cast a reference to an arbitrary type without generating at least an invalid cast exception at runtime (unless the cast is valid of course).
  • Harrow (unregistered) in reply to Cbuttius
    Cbuttius:
    ...put[ting] a null terminator on the end of your array... would be wrong anyway. What would happen if you call this multiple times?
    Two null terminators indicates the end of a string list or the end of a paragraph. Three nulls indicates the end of a document or file. Four nulls is end of directory, Five nulls is end of transmission or end of volume, and six nulls stands for the end of the working day.

    Seven nulls marks end of current employment. Eight nulls means time to retire and collect SS. Nine nulls specifies the end of the world as we know it.

    So calling it a few extra times may generate errors, which will probably be recoverable, but if you call it inside an infinite loop, it's curtains for all of us.

    Please use null terminators responsibly.

    -Harrow.

  • (cs) in reply to pitchingchris
    pitchingchris:
    I disagree. There are plenty of useful things you can do with operater overloading.
    But is there anything you can do with operator overloading that you can't do without it? Y'know, other than making your code harder to decipher for maintenance programmers? Operator overloading always seemed like self-indulgent syntactic sugar to me.
  • jMerliN (unregistered) in reply to Stev
    Stev:
    TRWTF is people complaining that a language "lets you shoot yourself in the foot". A gun will let you shoot yourself in the foot, much like a hammer will let you smash your thumb and a saw will let you cut your fingers off. C++ is a tool like any other and will cause a bloody mess if used without proper training or care, or if used in an inappropriate situation.

    You wouldn't use a chainsaw to slice a lemon in a cramped kitchen, nor would you use a carving knife to cut down a tree. C++ is no different - it has its place and where it is used appropriately it is positively unmatched. Likewise, when used inappropriately it'll cause massive amounts of bloodshed.

    The same can be said for just about any language. Deal with it.

    Your analogies are flawed. Any Turing complete language can let you shoot yourself in the foot. See: algorithmic complexity, bad code, etc. You compare a tool to a tool that has hidden tool-altering features that are invisible except on extreme introspection.

    The kind of "shoot yourself in the foot" C++ brings to the table is more like selling a gun to people and making it such that any person can modify where the bullet exits in a non-obvious manner (such as, it still looks like a gun but when you pull the trigger, it shoots directly at your feet). Then whenever you pick up a gun you haven't been the sole-owner and sole-possessor for its lifetime, you can't ever for sure know when you pull the trigger that it's not going to shoot your foot, unless you take it apart. Oh, and C++ also lets you universally modify how guns work, so anyone can just change how they fire, so now you have to deconstruct the entire universe to figure out if your gun will shoot you in the foot when fired.

    That's the WTF of C++. Changing the language's behavior in a manner that isn't immediately apparent without further introspection. And this breeds WTFs not present in other languages: APIs designed to be used via overloaded operators, so that there's not a well named function you can call to do a task (and thus avoid the use of operators with non-primitives, and again, you can overload operators on primitives, too, which is a whole other world of WTF). Things like needing to call myObj.operator++(...) explicitly to increment something because there's not a myObj.increment(). People do this. The very existence of this terrible feature leads to feature abuse and then feature reliance. We don't have the issues this "feature" causes in other languages. When we see code pasted in StackOverflow, we know what it does, not what it should do given the default operators.

    It's more like a hammer that has the "feature" of being able to have an invisible spring attachment so that when you hammer a nail, the hammer flies back into your face. It's not just a regular hammer, it's now an overloaded hammer, and one can argue the merits of such a hammer (two nails at once, if you position them right), but at the end of the day, it's still a massive WTF. It's novel, sure, but that doesn't make it any less of a WTF.

Leave a comment on “Lucky Pointing”

Log In or post as a guest

Replying to comment #:

« Return to Article