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. 



  • @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.



  • @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.


Log in to reply
 

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.