C++: Another Spoiled Newbie



  • I'm sorry to impose upon you all, as I'm sure I'm the millionth person to come here with questions like this. The fact is, it's hard for me to find people around here (a small town) who know anything about C++ (beyond a slight familiarity), and I really don't know where to turn with questions. (If there is a better place, you can let me know that too!)

     I'm a new programmer, still going to school, and I'm anxious to learn as much as I can. I also work as a junior programmer/general tech lackey for a small business. I've mainly focused on C#, and because of my job I'm pretty familiar with PHP and Ruby, but C++ has always interested me and recently I decided to actually start writing something in it. 

     A couple of questions that have come up so far, if you don't mind!

     What is an auto_ptr? I saw it in the C++ FAQ, but haven't seen it in most code examples on the web.

     When do I use references as opposed to pointers for function parameters?

    Should every "new" get a "delete"? (if that makes sense)

    Thanks in advance! 



  • I'm probably wrong on a bit of this, but auto_ptr stands for Auto Pointer; which is another way of saying a Smart Pointer (which is the term I'm used to using and thus will be using it from now on). Smart Pointers are called smart because they will free their memory when they are no longer used (all instances go out of scope), this is beneficial over dumb pointers which must be explicitly deleted/freed to prevent memory leaks. The Smart Pointer class I used is from Game Coding Complete (first edition) by Mike McShaffry it had a feature that would allow to send the SP as an argument (copy constructor) and a counter incremented indicating that two instances of it were in use and decremented when it should have been deleted (because there is still one instance in use). Also boost apparently has a few (iirc); but for all purposes merely writing a template class that has a few overload operators (* -> and &) with a constructor and deconstructor that handles memory allocation and deletion should take you 5-10 minutes. The reference counter feature is useless because you should actually be passing real references to the SP instead of using some built-in functionality.



    If you are passing an object as an argument you should always pass a reference (use const if you arn't changing it). If you don't a copy constructor is called and more memory than you need is used (usually minor but if the object is big it will hurt alot.



    Every new object should be deleted, you should use a smart pointer if necessary.



  • What is an auto_ptr? I saw it in the C++ FAQ, but haven't seen it in most code examples on the web.

    This is a really good explaination.  You don't see it in code samples because code samples purposefully trying to be simple to illustrate a single thing 

     

    When do I use references as opposed to pointers for function parameters?

    If you ask me, you should never use a reference. But then again, I'm a C programmer that learned C++, so I might be biased.  In the end, it compiles to the same code anyways...

     

    Should every "new" get a "delete"? (if that makes sense)

    Every object that is allocated on the heap with new (and every time you use new that is what you are doing) needs to be freed by delete.  HOWEVER, if you use smart pointers, the smart pointer will call delete for you.   Desiding who owns various objects is a very important design decision. Whomever owns the object should also delete it.



  • @tster said:

    If you ask me, you should never use a reference.

    Why?




    Also on the notes about new/delete make sure you are using the correct pair. If use use malloc/calloc/strdup/whatever_else_that_essentially_evaluates_to_malloc you have to use free. If you use new/new_nothrow (iirc thats what it is) you must use delete. If you use new []/new_nothrow [] you must use delete [].



    Also do not abuse smart pointers, sometimes an object needs to create another object within itself (like a wrapper around WinApi's BITMAP or any equivalent) that is a case were a smart pointer is useless the object that owns the BITMAP should behave like a smart pointer as it is. If you don't understand what I mean don't worry about it, I have a hard time explaining things in writing.



  • A couple things:

     A:  when passing an abject by value, it is not true that it will create a whole new object.  Modern compilers will make copies of only the parts that are changed.
     B:  When I say you should never do pass by reference I mean you should never do pass by reference as opposed to pass by pointer:

    I use:

    int function(MyClass * object);

    but I avoid:

    int function(MyClass & object);

    because the second one makes me forget that I am actually dealing with memory outside of my stack frame.  I like have to type object->  or (*object).  to remind myself (and later for ease of understanding it again) that I am about to cause side effects.
     



  • Thanks for the answers so far. I think for this little project I will avoid using smart pointers just so I can understand pointers better. A question though:

    I understand that I should call delete on things I assign with new; what about on things that I don't explicitly say 'new' for, like string and vector?



  • @tster said:

    When passing an abject by value, it is not true that it will create a whole new object.  Modern compilers will make copies of only the parts that are changed.

    It was my understanding that the copy constructor was to be called in that situation, and usually the copy constructor will copy the entire object (even if it has reserved 8MB of memory) and allocate more memory for the same data, which said constructor has no idea what will and will not be used.
    @tster said:
    I like have to type object->  or (*object).  to remind myself (and later for ease of understanding it again) that I am about to cause side effects.

    Again, if you pass all objects as references you don't run into a problem of trying to remember if it's was a reference or not. Generally the name of a variable should be a dead give away if it is an argument or not (if you are referring to the possibility of confusing the referenced argument with a local member/variable).



    nefigah> string and vector are basically Smart Pointers themselves they reference a character array and a variable-sized array respectively. By which I mean they call new and delete as necessary.



  • @tster said:

    I use:

    int function(MyClass * object);

    but I avoid:

    int function(MyClass & object);

    because the second one makes me forget that I am actually dealing with memory outside of my stack frame.  I like have to type object->  or (*object).  to remind myself (and later for ease of understanding it again) that I am about to cause side effects.

    Under normal circumstances, you should avoid using pass-by-reference like this. The primary exception is function(const X& object) - pass-by-const-reference is preferred to pass-by-value when the object is larger than a pointer. There are some more obscure exceptions when doing certain funky things with memory management; don't mess with them unless you understand them, but they are important when you really do need them (typically in applications that measure their memory usage in terabytes and their CPU load in megawatts).



  • @nefigah said:

    Thanks for the answers so far. I think for this little project I will avoid using smart pointers just so I can understand pointers better. A question though:

    I understand that I should call delete on things I assign with new; what about on things that I don't explicitly say 'new' for, like string and vector?

    Rule of thumb: if you didn't use new, don't use delete.  Use this rule until you start to realize that most (if not all) rules in C++ are merely suggestions.



  • @tster said:


     B:  When I say you should never do pass by reference I mean you should never do pass by reference as opposed to pass by pointer:

    I use:

    int function(MyClass * object);

    but I avoid:

    int function(MyClass & object);

    because the second one makes me forget that I am actually dealing with memory outside of my stack frame.  I like have to type object->  or (*object).  to remind myself (and later for ease of understanding it again) that I am about to cause side effects.

    I think this is just a "poor man's" implementation of const-ness (except it doesn't stop one from making mistakes) and may not be so good advice. All the tutorials I have read suggest using references over pointers as they are safer and have a more pleasant syntax.

    There are a few basic situations:

    1) You need a distinct copy of the object. Pass object.

    2) You want to modify the argument. Pass reference.

    3) You just want to avoid copying overhead and do not intend to modify the argument. Pass const reference. 

    4) Sometimes you want to pass a NULL pointer. Pass pointer. 



  • @nefigah said:

    Thanks for the answers so far. I think for this little project I will avoid using smart pointers just so I can understand pointers better. A question though:

    I understand that I should call delete on things I assign with new; what about on things that I don't explicitly say 'new' for, like string and vector?

    Always keep in mind that you're operating on two different areas in RAM: The heap and the stack. If you create an object using "new", you reserve a chunk of memory on the stack and store the start address of that memory in your pointer variable. You are solely responsible for managing heap memory. The OS will specifically not free heap memory for you, because it doesn't know if it's still needed or not. That's why you have to do this manually using "delete".

    Things are different for non-pointer variables inside functions. If you can a function, memory for its local variables is allocated on the stack, together with information about the called function. Because the life time of such an object is clearly defined - from the start of the function until the end of the function - it will be instantiated and deleted automatically for you. You don't need to use new or delete by yourself.

    Side note: Because such objects (in non-pointer variables!) are automatically freed when the procedure is exited, you should NEVER pass a pointer of them to something outside the function that could survive longer. Stupid example:

    int* foo() {

        int x; //Memory for one integer will be reserved
        x = 5; //Something gets written to that memory
        int* y = &x; //Allocate memory for y and sore the address of x there
        return y; //copy the contents of y (=the address of x) to the calling function and return. The memory for x and y gets freed automatically.

    }

    void main() {

       int* z = foo(); //Call foo
       doSomething(*z); //Try to dereference the pointer returned from foo(). That pointer points to memory inside the stack frame of the function call above. But since the call already returned, that frame doesn't exist anymore ==> Pain. Horrible pain.

    }

    Note that this wouldn't have happened if you had assigned the result of a "new" expression to y. Because then the OS wouldn't have freed your memory on return and main() could still dereference it.

    (If anything here is wrong, please correct me. It's some time already since I programmed in C++) 



  • @tster said:

    >When do I use references as opposed to pointers for function parameters?

    If you ask me, you should never use a reference. But then again, I'm a C programmer that learned C++, so I might be biased.  In the end, it compiles to the same code anyways...

    No no no no. It's the other way around. Always avoid using pointers when you can use a reference, and always use a const reference when you can - const correctness is a virtue.

    If you follow tsters suggestion then you will get all the disadvantages of naked pointers with none of the no-overhead memory-handling benefits C++ brings. References main advantage is that you're always guaranteed that what they're pointing to (referring to) exists. Pointers you can never be certain of.

    Pointers you should mainly use when doing internal low-level stuff, and they should never be exposed outside the low-level implementation. As parameters to functions you should always prefer references and always avoid pointers.

    Whenever you must use dynamically allocated memory, wrap the "new" inside a smart pointer object. Avoid storing naked pointers.

    This will make your code less bug-prone and much happier!



  • @Mikademus said:

    Pointers you can never be certain of.

    If you can't be certain what a pointer contains, step away from the computer. Seriously. You don't have what it takes to be a software developer.



  • Actually you can have references of invalid objects when returning references of local objects. But if you'd do that with references, you'd get the same results with pointers too (returning the address of a local object).

     

     

    If you can't be certain what a pointer contains, step away from the computer. Seriously. You don't have what it takes to be a software developer.

    This is a joke?

    You can't have uninitialized references (it is always a reference of something), you don't have to worry about null-ness, you can't accidentally reassign the reference and I guess you won't be "dereferencing" a reference that you have already "deleted". So references have several advantages over pointers. Unless you are particularly fond of chasing obscure bugs I see no reason to do things the harder way. 


  • Discourse touched me in a no-no place

    @PSWorx said:

    If you create an object using "new", you reserve a chunk of memory on the stack and store the start address of that memory in your pointer variable.

    :blink:

    Erm - no. Or at least I hope not. You're not involved with writing compilers, I hope.


    int* foo(){ return new int;}

    The object pointed to by the return of foo() should not be on the stack - it should be on the heap.

     

    Not that C or C++ Standards[tm] have the concept of heaps and stacks, but that's a different thread...



  • @PJH said:

    @PSWorx said:

    If you create an object using "new", you reserve a chunk of memory on the stack and store the start address of that memory in your pointer variable.

    :blink:

    Erm - no.

    Ack! I'm terribly sorry, that was some kind of gruesome typo. I meant heap, not stack. Of course you are right. 

    But the pointer returned by foo() does point to the stack - which causes the program to fail. That was the whole point I tried to make. 



  • @fist-poster said:


     

     

    If you can't be certain what a pointer contains, step away from the
    computer. Seriously. You don't have what it takes to be a software
    developer.

    This is a joke?

    You
    can't have uninitialized references (it is always a reference of
    something), you don't have to worry about null-ness, you can't
    accidentally reassign the reference and I guess you won't be
    "dereferencing" a reference that you have already "deleted".

    And you still don't know whether the value within the storage cell is correct or not.

    Software development is all about setting up fixed points in a complex system - creating software that will force certain values to be the ones that you want. If you cannot even manage to get the contents of a reference cell to be non-zero and current, then you have no hope at all of getting it to be the right value, so you cannot possibly create anything other than bugs.

    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    Don't be that guy.


  • Discourse touched me in a no-no place

    @PSWorx said:

    @PJH said:

    @PSWorx said:

    If you create an object using "new", you reserve a chunk of memory on the stack and store the start address of that memory in your pointer variable.

    :blink:

    Erm - no.

    Ack! I'm terribly sorry, that was some kind of gruesome typo. I meant heap, not stack. Of course you are right. 

    But the pointer returned by foo() does point to the stack - which causes the program to fail. That was the whole point I tried to make. 

    No it shouldn't. You've just repeated (in a different way) what you said in your first quotation. Either that, or I'm failing to understand what you're trying to say.

    If you're allocating memory on the heap, then the pointer returned for that memory must be pointing into the heap.

    The only things allocated on the stack are automatic variables and memory reserved with alloca(), thus their addresses will be in stack space.
     



  • @asuffield said:

    If you can't be certain what a pointer contains, step away from the
    computer. Seriously. You don't have what it takes to be a software
    developer.

    ...

    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    You're trying to pin all that on me? Wow, your imagination and mistrust of others seem to be of paranoid proportions. Assufield, many comments you've made here at TDWTF have been good and readworthy, but now you just seem like an ass with anger issues. Next time, don't read always assuming the worst, doing your damndest to intentionally misunderstand what's written to try to score pathetic e-penis one-upper replies. If one had to write to the negatively biased reader you represent in this thread then all internet exchanges would degenerate into legalese or flamewars.

    Don't be that guy.

    Qft.



  • @PJH said:

    @PSWorx said:

    But the pointer returned by foo() does point to the stack - which causes the program to fail. That was the whole point I tried to make. 

    No it shouldn't. You've just repeated (in a different way) what you said in your first quotation. Either that, or I'm failing to understand what you're trying to say.

    If you're allocating memory on the heap, then the pointer returned for that memory must be pointing into the heap.

    The only things allocated on the stack are automatic variables and memory reserved with alloca(), thus their addresses will be in stack space.

    I think you are actually talking about two different int* foo()  ;-)

    @PSWorx said:

    int* foo() {

        int x; //Memory for one integer will be reserved
        x = 5; //Something gets written to that memory
        int* y = &x; //Allocate memory for y and sore the address of x there
        return y; //copy
    the contents of y (=the address of x) to the calling function and
    return. The memory for x and y gets freed automatically.

    }

    In this function x (and y) is allocated on the stack, thus the returned pointer is to the stack.

     

    @PJH said:

    int* foo(){ return new int;}

    Here the returned pointer is to somewhere in the heap.



  • @PJH said:

    The only things allocated on the stack are automatic variables and memory reserved with alloca(), thus their addresses will be in stack space.

    Not all implementations of alloca() use the stack. And, technically, "register" variables are allowed to be on the stack. the keyword is simply a [mostly worthless these days] compiler hint. 



  • @asuffield said:

    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    There's nothing desperate about trying to find an existing solution to a problem.  Why waste your energy reinventing the wheel, especially when there's a nice one right there next to you?

    On a related note, while you may feel that we must be grateful that you have deigned to let us bathe in the glory of your wisdom, your recent MO of posting smug invectives seems misguided at best.



  • @olm said:

    @PJH said:
    @PSWorx said:

    But the pointer returned by foo() does point to the stack - which causes the program to fail. That was the whole point I tried to make. 

    No it shouldn't. You've just repeated (in a different way) what you said in your first quotation. Either that, or I'm failing to understand what you're trying to say.

    If you're allocating memory on the heap, then the pointer returned for that memory must be pointing into the heap.

    The only things allocated on the stack are automatic variables and memory reserved with alloca(), thus their addresses will be in stack space.

    I think you are actually talking about two different int* foo()  ;-)

    @PSWorx said:

    int* foo() {

        int x; //Memory for one integer will be reserved
        x = 5; //Something gets written to that memory
        int* y = &x; //Allocate memory for y and sore the address of x there
        return y; //copy
    the contents of y (=the address of x) to the calling function and
    return. The memory for x and y gets freed automatically.

    }

    In this function x (and y) is allocated on the stack, thus the returned pointer is to the stack.

     

    @PJH said:

    int* foo(){ return new int;}

    Here the returned pointer is to somewhere in the heap.

    Exactly. 



  • Thanks everyone again for the replies. I would be lying if I said I still wasn't a bit confused (mainly due to differing opinions posted), but I guess if nothing else it seems like there is more than one way to skin a cat. But things seem to be working so far :)

    I'm still slightly confused about header files; they are still foreign to me. In Visual Studio when I add a class it automatically creates a header file for that class, so I've just been doing that approach. No idea if I'm supposed to be combining them or what. But, it compiles at least :o 



  • @bstorer said:

    @asuffield said:

    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    There's nothing desperate about trying to find an existing solution to a problem.  Why waste your energy reinventing the wheel, especially when there's a nice one right there next to you?

    There's a difference between trying to find an existing solution to a problem, and avoiding a problem because it's "too hard". Most of the time in software development, if you can't solve the problem yourself, you shouldn't be messing with it. This is one of those times. That does not necessarily mean that you have to solve the problem yourself every time it comes up. 


  • Discourse touched me in a no-no place

    @olm said:

    I think you are actually talking about two different int* foo()  ;-)

     

    Oops - my fault then. 



  • @asuffield said:

    @bstorer said:

    @asuffield said:

    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    There's nothing desperate about trying to find an existing solution to a problem.  Why waste your energy reinventing the wheel, especially when there's a nice one right there next to you?

    There's a difference between trying to find an existing solution to a problem, and avoiding a problem because it's "too hard". Most of the time in software development, if you can't solve the problem yourself, you shouldn't be messing with it. This is one of those times. That does not necessarily mean that you have to solve the problem yourself every time it comes up.

    I don't think that's the case here.  "You shouldn't be messing with it"?  What exactly are we not messing with?  Pointers?  References?  The fact is that references serve a nice purpose.  Perhaps they're less efficient in terms of performance, but they provide me some assurances that pointers don't.  That's a trade-off that is often worthwhile.



  • @bstorer said:

    References?  The fact is that references serve a nice purpose.  Perhaps they're less efficient in terms of performance, but they provide me some assurances that pointers don't.  That's a trade-off that is often worthwhile.

    There's nothing less efficient about references than pointers. References are pointers, only subject to more draconian checks at compile-time  In fact, using references when possible should make your code more efficient since you will not need to accumulate a lot of "if (pSomePointer) {...}" checks

     PS. Ass-u-field, if you feel the urge to reply to this with some besserwisser minutiae or other pompous crap, don't.
    .



  • @Mikademus said:

    @bstorer said:

    References?  The fact is that references serve a nice purpose.  Perhaps they're less efficient in terms of performance, but they provide me some assurances that pointers don't.  That's a trade-off that is often worthwhile.

    There's nothing less efficient about references than pointers. References are pointers, only subject to more draconian checks at compile-time  In fact, using references when possible should make your code more efficient since you will not need to accumulate a lot of "if (pSomePointer) {...}" checks

     PS. Ass-u-field, if you feel the urge to reply to this with some besserwisser minutiae or other pompous crap, don't.

    I haven't used C++ in any real capacity in six years or more, so forgive anything I've forgotten.  But if references are only more time consuming at compile time, then there's really no reason not to use them.  I'm with you all the way (actually, I was before, when I still thought there was some overhead to them).

    EDIT: Also, nice use of "besserwisser!"



  • @Mikademus said:

    @bstorer said:

    References?  The fact is that references serve a nice purpose.  Perhaps they're less efficient in terms of performance, but they provide me some assurances that pointers don't.  That's a trade-off that is often worthwhile.

    In fact, using references when possible should make your code more efficient since you will not need to accumulate a lot of "if (pSomePointer) {...}" checks

    References do not remove the need to check for invalid pointers, since they're just a more obtuse way of writing pointers. References can be assigned both NULL and invalid values.



  • @asuffield said:

    @Mikademus said:
    @bstorer said:

    References?  The fact is that references serve a nice purpose.  Perhaps they're less efficient in terms of performance, but they provide me some assurances that pointers don't.  That's a trade-off that is often worthwhile.

    In fact, using references when possible should make your code more efficient since you will not need to accumulate a lot of "if (pSomePointer) {...}" checks

    References do not remove the need to check for invalid pointers, since they're just a more obtuse way of writing pointers. References can be assigned both NULL and invalid values.

    The problem with this statement (and the post you replied to is that there's about a dozen different things called "References", which are all pointers, restricted in a dozen different ways. A C++ reference cannot be assigned NULL or an invalid value. I'm not aware of any language with something called a "reference" that can be assigned an invalid value or uninitialized, though they probably exist.



  • @Random832 said:

    A C++ reference cannot be assigned NULL or an invalid value.

    A common belief in the "pointers are evil, use references instead" crowd. It's wrong (and they're idiots), and the source of a stupid number of segfaults created by ignorant people.

    NULL reference:

      fprintf(stderr, "1\n");
      int *a = 0;
      fprintf(stderr, "2\n");
      int &b = *a;
      fprintf(stderr, "3\n");
      b = 1;
      fprintf(stderr, "4\n");

    Most compilers will generate code that gets up to 3 and then crashes on the line "b=1;".

    Invalid value in a reference (this is the one that commercial C++ idiots do all the time):

      int *a = new int;
      int &b = *a;
      delete a;
      b = 1;

    References are just a syntax disguise for pointers. Almost every compiler just switches the types to pointers and moves the *s around, as if you had just written:

      int *a = new int;

      int *b = a;

      delete a;

      *b = 1;

    So the behaviour is identical to the pointer version, and all you accomplish by using references is to make the true behaviour of the code harder to understand, and mislead the reader into thinking it does something else.



  • Way to go making everyone else seem stupid and yourself seem smart by intentionally misinterpreting posts in your eternal quest of one-upmanship. As was said, you can't assign a reference to NULL. You can of course assign a reference to the dereference of a bad pointer, or any variety of that. And language feature can be misused by bad programming. Also, way to go on your other eternal quest to divide the world into black-and-white (with, in the extension, everyone but you being idiots), since I now apparently belong to the (idiot) "'pointers are evil, use references instead' crowd", which is news to me. Tell me, do you actually yourself believe the sad interpretations you make of people by fantasising and extrapolating from their posts, or are you just using the internet to take out real-life frustration and anger on people you will never have to face? You're pompous, seldom constructive and never inspiring in your posts.

    You said it, "don't be that person!"

    Dixi 



  • @asuffield said:

    @Random832 said:

    A C++ reference cannot be assigned NULL or an invalid value.

    A
    common belief in the "pointers are evil, use references instead" crowd.
    It's wrong (and they're idiots), and the source of a stupid number of
    segfaults created by ignorant people.

    NULL reference:

      fprintf(stderr, "1\n");
      int *a = 0;
      fprintf(stderr, "2\n");
      int &b = *a;
      fprintf(stderr, "3\n");
      b = 1;
      fprintf(stderr, "4\n");

    And
    this code "fails" (introduces undefined behaviour) at the point where
    you dereference a NULL pointer - even before you get to references.
    Note that with references, errors of this kind simply won't happen.

    Invalid value in a reference (this is the one that commercial C++ idiots do all the time):

    I assume the pointer equivalent is what "C idiots" do all the time? 

     

      int *a = new int;
      int &b = *a;
      delete a;
      b = 1;

    References
    are just a syntax disguise for pointers. Almost every compiler just
    switches the types to pointers and moves the *s around, as if you had
    just written:

      int *a = new int;

      int *b = a;

      delete a;

      *b = 1;

    So
    the behaviour is identical to the pointer version, and all you
    accomplish by using references is to make the true behaviour of the
    code harder to understand, and mislead the reader into thinking it does
    something else.

    Exactly why? Just because you
    don't understand references? In both cases you'll need to know that
    there is a problem because b is either a reference of a or pointing to
    a that got deleted. If there is sufficient amount of code between these
    lines, that would be equally hard to find out. If there is enough code
    between, may-be it just happened that the pointer b got reassigned to
    point some place else? Or may-be it didn't? 



  • @fist-poster said:

    And
    this code "fails" (introduces undefined behaviour) at the point where
    you dereference a NULL pointer - even before you get to references.
    Note that with references, errors of this kind simply won't happen.

    Still wrong. 

    int &a(void) {
      int b;
      return b;
    }

    It breaks just as easily without using any pointers. References are not "safe".

    Invalid value in a reference (this is the one that commercial C++ idiots do all the time):

    I assume the pointer equivalent is what "C idiots" do all the time? 

    I have not observed a trend for stupid C programmers to believe that the pointer b is still valid after a has been deleted, so no.

     

    So
    the behaviour is identical to the pointer version, and all you
    accomplish by using references is to make the true behaviour of the
    code harder to understand, and mislead the reader into thinking it does
    something else.

    Exactly why? In both cases you'll need to know that
    there is a problem because b is either a reference of a or pointing to
    a that got deleted.

    In the case where references are used, the point at which the program crashes is a simple variable assignment. Many C++ programmers believe you can't have invalid or NULL references, so they will fail to understand what is happening. My observation is that they usually blame hardware faults or compiler bugs.



  • @asuffield said:

    @fist-poster said:

    And
    this code "fails" (introduces undefined behaviour) at the point where
    you dereference a NULL pointer - even before you get to references.
    Note that with references, errors of this kind simply won't happen.

    Still wrong. 

    int &a(void) {
      int b;
      return b;
    }

    It breaks just as easily without using any pointers. References are not "safe".

    Now this is a more realistic example. But the exact same error is possible with pointers too:

    int* a() {

      int b;

      return &b;

    }

    I  think once you have been told and understand why you shouldn't do this, that won't be a problem any more.

    I
    have not observed a trend for stupid C programmers to believe that the
    pointer b is still valid after a has been deleted, so no.

    Well, I haven't noticed this kind of misunderstanding with C++ programmers either (from what I have seen in programming boards).

    Anyway,
    if you are in a situation where you have multiple references (pointers)
    to memory that might get deallocated all of a sudden somewhere, you are
    already on rather thin ice. As a hobby programmer I have managed to
    avoid such situations entirely (by not allocating and deallocating
    memory at some random places, by not trying to store for example
    iterators to data that might be moved etc), but if it were not
    possible, I guess one should use some sort of smart pointers over naked
    pointers anyway.

    In the case where references are used, the point at which the program crashes is a simple variable assignment. Many C++ programmers believe you can't have invalid or NULL references, so they will fail to understand what is happening. My observation is that they usually blame hardware faults or compiler bugs.

    Again, I'm not sure why there should be multiple references to the same thing in this case (I think the discussion started from how one should pass large objects to functions). But the problem starts from dereferencing a NULL pointer, which will appear to work as you have observed, and that is precisely a problem with pointers. With references the language forces you to initialize them with something valid - unless you bring in NULL pointers or something insane like that.

    If your fellow programmers understand the language that poorly, they should be taught, and not limited to the simplest but unsafest features of the language. 

    There are certainly a number of situations where you absolutely must use pointers (and then certain practices such as RAII principles and use of smart pointers can make it safer), but if you have a choice (as in how to avoid copying large objects when you pass them to functions) it seems wiser to prefer a higher level construct that enforces stricter rules.



  • @fist-poster said:

    But the exact same error is possible with pointers too:

    int* a() {

      int b;

      return &b;

    }

    I  think once you have been told and understand why you shouldn't do this, that won't be a problem any more.

    I know that I wasn't the one bitching about how pointers were too hard to work with.

    Anyway,
    if you are in a situation where you have multiple references (pointers)
    to memory that might get deallocated all of a sudden somewhere, you are
    already on rather thin ice. As a hobby programmer I have managed to
    avoid such situations entirely (by not allocating and deallocating
    memory at some random places, by not trying to store for example
    iterators to data that might be moved etc), but if it were not
    possible, I guess one should use some sort of smart pointers over naked
    pointers anyway.

    In any kind of serious project, you're going to need to tackle the resource management problem at some point, rather than just avoiding it.

    With references the language
    forces you to initialize them with something valid - unless you bring
    in NULL pointers or something insane like that.

    It really doesn't force you to do anything of the kind. You're free to initialize them with anything you like, valid or otherwise.

     

    If your fellow
    programmers understand the language that poorly, they should be taught,
    and not limited to the simplest but unsafest features of the
    language.

    You seem confused. I have already indicated that such people should be transferred to buildings maintenance, and kept away from the computers. (You can't teach an idiot to fly aircraft, build bridges, or create software that doesn't set things on fire)

     

    but if
    you have a choice (as in how to avoid copying large objects when you
    pass them to functions) it seems wiser to prefer a higher level
    construct that enforces stricter rules.

    C++ references do not enforce anything. They are just alternate syntax for pointers.



  • @asuffield said:

    I know that I wasn't the one bitching about how pointers were too hard to work with.

    No one said that. It was simply your people-loathing brain that conjured up that interpretation.  

    In any kind of serious project, you're going to need to tackle the resource management problem at some point, rather than just avoiding it.
    There you go again, practising the ancient art of debate hand waving through ostensibly meaningful but really non sequitur replies when you have been shown to be NULL and void and have nothing relevant to say but still want to be on top, at least in your own perception.

    You've degenerated into less than a troll: a troll without self-insight. If there was an "ignore user" button on Community Server, guess how many would be reading your posts...



  • A variant of one of the earlier examples:

    int* p = new int;
    int* q = p;
    //..Somewhere
    delete q;
    //..Somewhere further down
    *p = 42; //Huh

    Supposing it was a programmers bug to delete q. Now what would it take to make the same mistake if q was a reference?

    @asuffield said:

    In any kind of serious project, you're going to need to tackle the resource management problem at some point, rather than just avoiding it.

    Um, I was saying that resource management has so far never been a problem for me... I have avoided problems, not managing resources.

    It really doesn't force you to do anything of the kind. You're free to initialize them with anything you like, valid or otherwise.

    C++ references do not enforce anything. They are just alternate syntax for pointers.

    Then why does the compiler complain when I do:

    int& a;

    And even then, having a cleaner syntax (for example without a trace of doubt whether the coder intended to dereference the pointer or not) is a great improvement where applicable.



  • Just to add this one:

    With a pointer you have two things to manage: the pointer itself and what it is pointing to. You can dereference a pointer and increment the value or you can increment the pointer itself.

    With a reference you only have the value to look after.

    If you only want the value (without the copying overhead), it wouldn't make sense to add another level of complexity, because "references are just disguised pointers". 



  • @Mikademus said:

    @asuffield said:

    I know that I wasn't the one bitching about how pointers were too hard to work with.

    No one said that.

    @Mikademus said:

    Pointers you can never be certain of.

    Pretty obvious to me that this is a complaint about the difficulty of understanding how pointers work. 



  • @fist-poster said:

    And
    even then, having a cleaner syntax (for example without a trace of
    doubt whether the coder intended to dereference the pointer or not) is
    a great improvement where applicable.

    I've already shown several examples where references make it harder to understand what is going on, because they hide the indirection. It's not cleaner, just different.


    With a reference you only have the value to look after.

    References, like every other storage-cell type, involve both their own address and the address of their contents. I count two values there. 



  • @asuffield said:

    @Mikademus said:

    @asuffield said:

    I know that I wasn't the one bitching about how pointers were too hard to work with.

    No one said that.

    @Mikademus said:

    Pointers you can never be certain of.

    Pretty obvious to me that this is a complaint about the difficulty of understanding how pointers work. 

    The only obvious thing is that you are an utter twat and insufferable bore that by your own words just proved all my above suppositions about you.



  • @asuffield said:

    @fist-poster said:

    And
    even then, having a cleaner syntax (for example without a trace of
    doubt whether the coder intended to dereference the pointer or not) is
    a great improvement where applicable.

    I've already shown several examples where references make it harder to understand what is going on, because they hide the indirection. It's not cleaner, just different.


    Ok, an example, swapping two values.

    With references:

    void swap(int& a, int& b)
    {
        int temp = a;
        a = b;
        b = temp;
    }

    Other than the & in the parameters, it is no different than swapping two local variables.

    With pointers:

    void swap(int* a, int* b)
    {
        int temp = *a;
        *a = *b;
        *b = temp;
    }

    Since here it is the coder's responsibility to dereference the pointers properly, there are many places to make both syntax and logical mistakes. For example a nice runtime error:

     void swap(int* a, int* b)

    {

        int temp = *a;

        a = b;

        *b = temp;

    }

    As in this case the programmer is only interested in the
    dereferenced values, forcing manual dereferencing is just distracting
    noise.

    Any C++ programmer needs to be able to work with pointers
    anyway, so the claims that "reference-preferring people" don't
    understand pointers is rather absurd. There simply is no point in
    choosing pointers where you don't need their functionality, as the only
    thing it can do is add noise and increase bug-count.


    With a reference you only have the value to look after.

    References, like every other storage-cell type, involve both their own address and the address of their contents. I count two values there. 

    Funnily, I don't think about references as pointers at all. For me it is the exact same thing it is a reference of  - with a different name. I haven't heard of "reference arithmetics" and I'm looking forward to an example how to reseat a reference.

    I guess, if you want to, you may consider anything to be a pointer in C and C++, but I can't see what practical conclusions you can draw from it. Plain old stack variables "hide" the same indirection too, but I find it more productive to think in terms of "firstName" and "lastName", rather than "memory at offset n".

     



  • @asuffield said:

    You don't have what it takes to be a software developer.

    @Mikademus said:
    You just seem like an ass with anger issues [...]
    Ass-u-field

    @bstorer said:
    Your recent MO of posting smug invectives seems misguided at best.

    @fist-poster said:
    You don't understand references [...]
    You've degenerated into less than a troll

    This starts to look like a pissing contest.

    To Mikademus, bstorer, fist-poster:
    Asuffield is right: references are not safer than pointers and are primarily syntactic sugar that sometimes (operator overloading) makes your code easier to read, but often merely obfuscates it. Compilers will only protect from blatant typos, if at all. If you don't believe him or me, read second opinions by Bjaerne Stroustrup or Dan Saks.

    Don't try to beat asuffield on his home ground: he knows more about this stuff than all of us put together.

    To asuffield:
    You'll stand a better chance that people will listen to you if you wouldn't start your rethoric with insults.



  • @JvdL said:

    To Mikademus, bstorer, fist-poster:

    Asuffield is right: references are not safer than pointers and are primarily syntactic sugar that sometimes (operator overloading) makes your code easier to read, but often merely obfuscates it.
    Compilers will only protect from blatant typos, if at all. If you don't believe him or me,
    read second opinions
    by Bjaerne Stroustrup
    or Dan Saks.

    References are safer than pointers when not used in conjunction with pointers.  Every example of a reference failing here is from a reference to a pointer or pointed object.  Here's an interesting thought: don't use references in that way.  This is like complaining, "It causes problems when allocating memory with malloc and trying to free with with delete!"  You think so, doctor?  The solution is not to ban the use of malloc, or declare it lazy and stupid to use delete.  Saks himself says:

    <font face="Verdana" size="2">I like references. There are good reasons
    to use them instead of pointers. But, if you expect that using
    references will make your program significantly more robust, you're
    likely to be disappointed.
    </font>

    Exactly how I feel.  References are certainly easier and cleaner in some cases.  I support using them in those cases.  I don't think anyone really suggests eschewing pointers for references altogether, because that's just stupid.



  • @bstorer said:

    Every example of a reference failing here is from a reference to a pointer or pointed object.

    Example given by asuffield as well as Dan Saks: int &f(){int i;return i;} is a failing reference, no pointers involved. Not sure what you mean by "pointed object" other than something involving pointers.

    @bstorer said:

    Exactly how I feel.  References are certainly easier and cleaner in some cases.

    So do I. So does assufield. So what's the shouting about? Probably, about what amounts to some cases.
    Other than operator overloading and similar f(T&x) declarations, which was Stroustrup's only original purpose, I've seen little to show for references.

    "If there is an elephant in the room, you better introduce him" (Randy Pausch)



  • @JvdL said:

    @bstorer said:
    Every example of a reference failing here is from a reference to a pointer or pointed object.
    Example given by asuffield as well as Dan Saks: int &f(){int i;return i;} is a failing reference, no pointers involved.

    Fair enough; I missed asuffield's comment where he mentioned that.  I had forgotten you could do such a thing, because I never do it.  I hate C++ sometimes.

    Not sure what you mean by "pointed object" other than something involving pointers.

    I mean "that which is pointed to", a lazy way to acknowledge all the examples like int & b = *a; delete a; ++b;

    To be honest, in rereading some of this, my main complaint with asuffield was this response to fist-poster:

    @asuffield said:


    Flailing around to try and find a mechanism that allows you to avoid uninitialised and null values, in a desperate attempt to avoid having to solve any problems yourself, is like a soldier trying to fight a war by bashing his gun with a rock. Several dozen friendly fire casualties later, he proudly proclaims that he got it to fire on demand, and thinks he has accomplished something.

    Don't be that guy.

     

    Which strikes me as infuriatingly smug.  Especially considering that fist-poster had, earlier in the thread, said this:

    @fist-poster said:

    There are a few basic situations:

    1) You need a distinct copy of the object. Pass object.
    2) You want to modify the argument. Pass reference.
    3) You just want to avoid copying overhead and do not intend to modify the argument. Pass const reference.
    4) Sometimes you want to pass a NULL pointer. Pass pointer.

    Those rules dovetail nicely with what Dan Saks says in the article you linked.

     

    Other than operator overloading and similar f(T&x) declarations, which was Stroustrup's only original purpose, I've seen little to show for references.

    It's clear from the above (and the relevant discussion) that we're talking about using references as a function parameter.  Anyone suggesting references be used in other contexts is on his (or her) own, because you won't get any support from me.



  • There is also the theoretic possibility to use references as return values - if you desperately need things like foo(5) = 42;

    But other than to confuse/baffle your coworkers, I don't see much practical reason for it either. 



  • @PSWorx said:

    There is also the theoretic possibility to use references as return values - if you desperately need things like foo(5) = 42;

    But other than to confuse/baffle your coworkers, I don't see much practical reason for it either. 

    Damn it :)

    Again, I find something like

    std::string s = "hello";

    s[0] = 'z';

    rather convenient and readable.

    (I learnt to program in a BASIC where the above would be written as s$ = "z" + MID$(s$, 2) )

    As
    far as the "safety" of using references for function parameters goes, I
    find that it is easier on my eyes and fingers and that it gives me less
    chances to make stupid syntax errors (if nothing worse). If I'm unsure
    whether a function might have side-effects, I have no problem looking
    up the prototype.

    Of course I didn't mean that if the calling
    code is full of nonsense, my tiny little function would magically fix
    that as well. Hence the analogy of "friendly fire" seemed rather
    non-sense where I thought I was suggesting to put the safety lock on if
    you don't intend to shoot anybody...


Log in to reply