Thread: somefunc(int& a = 4) -> default argument for ‘int& a’ has type ‘int’

  1. #16
    The larch
    Join Date
    May 2006
    Posts
    3,573
    The idea with the global variable seems rather bad advice in my opinion. You are going to have an empty vector as a class member only to use it as a default argument for some function?

    If you won't change the vector, make it a const reference.

    If you do, the overload suggested by cpjust makes more sense. I must concede that in some situations all this might be no more fallacious than ignoring return values (the vector is modified, but you don't care unless you pass it in yourself). Things happening implicitly can lead to bugs, though...
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  2. #17
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> I'm not convinced of that; a function that accepts an argument by non-const reference, and modifies an argument that is not passed (should that be allowed) would reasonably be expected to exhibit spurious behaviour.

    I honestly don't know what you mean here, can you rephrase?

    I'm not sure what the discussion is about. This seems like a textbook example of when to use a pointer parameter, and I'm glad hardi has gotten the code to work with the pointer. I must be missing something because I don't understand any of the peripheral discussion.

  3. #18
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Daved View Post
    >> I'm not convinced of that; a function that accepts an argument by non-const reference, and modifies an argument that is not passed (should that be allowed) would reasonably be expected to exhibit spurious behaviour.

    I honestly don't know what you mean here, can you rephrase?
    Let me rephrase as a question.

    somefunc() accepts a variable by reference, and modifies it. The default argument specification means that constant is passed if the caller does not provide an actual argument. What behaviour do you expect somefunc() to exhibit when it modifies the argument it receives?

    The original question is about why a compiler complains at the notion of passing a constant value by default to a function that is expecting a non-const reference.

  4. #19
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    Why use pointers when you can just write another function that calls the other one using an empty vector?

  5. #20
    The larch
    Join Date
    May 2006
    Posts
    3,573
    With pointers?

    I can think of two ways to meet OP's requirements (using an empty vector - but this could be an int as well - as a default and modifying it in the function):
    Code:
    void foo(std::vector<int>* vec = new std::vector<int>())
    {
        //use and modify *vec
    }
    
    void bar(std::vector<int>* vec = 0)
    {
        bool is_null = !vec;
        if (is_null)
            vec = new std::vector<int>();
            
        //use and modify *vec
        if (is_null)
            delete vec;
    }
    Now, the first one is elegant, but seems to create an unavoidable memory leak as there is no way of telling whether a vector pointer was passed or not.

    The second one is ugly but hopefully correct.

    Given these options I would drop the requirement of a default parameter altogether:
    Code:
    void foo(std::vector<int>& vec);
    
        //calling with an empty "default"
        std::vector<int> empty_vec;
        foo(empty_vec);
    (The idea with a function overload is the same: if you call the overload that takes no arguments, that would create the empty vector for you and call the main version that takes a vector and does the real work.)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  6. #21
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> What behaviour do you expect somefunc() to exhibit when it modifies the argument it receives?
    It doesn't matter. It's not legal. Compilers that support it probably create a temporary object and allow it to be modified.

    My point was that the logic of the function (without respect to the type of the parameter) was completely valid, it is just not something that should be accomplished with references.

    Even if (and when) it is allowed with references, a valid result is still possible. If you check the value against the default literal value and only modify it if it is not that, then you will be fine and no spurious behavior will result. The actual example the OP is using involves an empty vector that will be left untouched if it is empty. It makes perfect sense to think that it might be possible to do that with references in C++, it just turns out that you can't in a standard way and you should use pointers instead.

  7. #22
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    There are two logical solutions I can think of. One is to use references and overload as has been suggested by others here:
    Code:
    void some_func(std::vector<int>& v)
    {
    }
    
    void some_func()
    {
      std::vector<int> v;
      some_func(v);
    }
    The other is to use a pointer. Using the pointer has the advantage of better documenting the optionality of the argument. With overloading, it is not obvious that the functions do the same thing. With the pointer solution, it is obvious that at least they use the same code. In addition, the pointer makes it obvious that the argument passed in can be modified. Using a reference for this is slightly less obvious.
    Code:
    void some_func(std::vector<int>* pv = 0)
    {
    }
    The downside of course is the more difficult syntax, although you can always create a reference to the vector after checking for null if you prefer non-pointer syntax.
    Last edited by Daved; 08-29-2007 at 03:33 PM. Reason: Fixed thanks to anon.

  8. #23
    The larch
    Join Date
    May 2006
    Posts
    3,573
    In the first one you should have the overload like that:
    Code:
    void some_func()
    {
      std::vector<int> vec
      some_func(vec);
    }
    Creating non-const references out of temporaries should not be allowed and GCC treats it as an error.

    As to the pointers, see my post above. Pointers are good if you want a null-pointer to represent an invalid object / lack of object. But in this case it seems that the OP doesn't want an invalid object - he wants a valid non-const default object.

    And ability to use some syntactic sugar doesn't seem like a good reason to use pointers in a program...
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #24
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Or rather, like this.
    Code:
    void some_func()
    {
      std::vector<int> vec;
      some_func(vec);
    }
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  10. #25
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> Creating non-const references out of temporaries should not be allowed and GCC treats it as an error.
    You're right. It's the same error we were trying to avoid in the first place.

    >> Pointers are good if you want a null-pointer to represent an invalid object / lack of object.
    This is exactly what the OP wants.

    >> he wants a valid non-const default object.
    No, he doesn't plan to modify the default object. He will modify the parameter only if the default argument is not passed in.

    So, the function can take a vector from the user. If the vector is not empty, it is modified. The function can also take no parameters from the user. In that case, the default parameter would be an empty vector, which is not modified.

    In this case, the OP hoped that an empty vector used as the default parameter could represent the lack of an object. It cannot. But as you said that is what pointers are for.

  11. #26
    and the hat of sweating
    Join Date
    Aug 2007
    Location
    Toronto, ON
    Posts
    3,545
    If you do decide to use pointers in this case, you should use an std::auto_ptr to ensure the temporary pointer is deleted (or don't create a new vector in the first place if just checking for NULL will do):

    Code:
    void bar( std::vector<int>* vec = NULL )
    {
        std::auto_ptr< std::vector<int> > auto_vec;
    
        if ( vec == NULL )
        {
            auto_vec = new std::vector<int>;
        }
    
        // Now just relax and let auto_ptr delete the ptr for you.
    }
    That way, if an exception is thrown inside the function, the pointer will still get deleted.

  12. #27
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    I think in this case if the value is null then the code that modifies the vector would be skipped. There would be no point in dynamically allocating a temporary vector whose changes (if any) would be ignored. Note that in post #5 hardi said that if the default value is used the vector would not be modified.

    In other words, you don't have to worry about deleting the pointer, because there shouldn't be any newing of a pointer in the first place.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. pointer to array of objects of struct
    By undisputed007 in forum C++ Programming
    Replies: 12
    Last Post: 03-02-2004, 04:49 AM
  2. Erros in Utility Header File
    By silk.odyssey in forum C++ Programming
    Replies: 4
    Last Post: 12-22-2003, 06:17 AM
  3. header file bringing errors?
    By bluehead in forum Windows Programming
    Replies: 4
    Last Post: 08-19-2003, 12:51 PM
  4. Warnings, warnings, warnings?
    By spentdome in forum C Programming
    Replies: 25
    Last Post: 05-27-2002, 06:49 PM
  5. gcc problem
    By bjdea1 in forum Linux Programming
    Replies: 13
    Last Post: 04-29-2002, 06:51 PM