Is it a good practice to use temporary objects as arguments when overloading functions?

StackOverflow https://stackoverflow.com/questions/20931581

  •  24-09-2022
  •  | 
  •  

Given prototypes:

void foo(int i);
void foo(int i, const std::string &s);

Implementation:

void foo(int i)
{
    foo(i, std::string())   ;
    //!    ^^^^^^^^^^^^^    ^ here?

    //  nothing more.

      }
//!   ^  here?

void foo(int i, const std::string &s)
{
    //do something
}

Where does the temporary object created by std::string() go out of scope? Is it a good practise to overload functions this way?

Update:

Let me explain a little bit of the situation. As an exercise, I'm trying to write a class like a std::vector without using a template. The only type it holds is std::string. The class body can be found in another question.

When implementing the resize() member function, I found that std::vector seems are using two functions:

  void 
  resize(size_type __new_size);
  void
  resize(size_type __new_size, const value_type& __x);

So I'm wondering whether I should use two functions instead of a single one.

有帮助吗?

解决方案 2

I don't think it's bad practice, especially if you make foo(int i) inline. I can think of a reason when this is preferred: when you create pointers to function, if you declare the second parameter default, you can have only pointer to function that accepts 2 parameters.

The temporary value is alive only as the parameter for the function call.

inline void foo(int i)
{
  foo(i, std::string());
}

void foo(int i, const std::string &s)
{
    //do something
}

其他提示

No, it's not a good practice, at least in this particular case. Use a single function, and a default value for the argument, rather than two functions, one of which only seems to exist to supply a default argument:

void foo(int i, const std::string &s = "")
{
    //do something
}

The only "danger" in passing a temporary as const& happens if the function creates an object that survive the function call itself that stores in itself a const&.

Think to

class A
{
   const string& a;
public:
   A(const string& a) :a(a) {}
   void act() { .... /* use a */ }
};

A* foo(const string& s)
{ return new A(s); }

int main()
{
   A* pa = foo(string());
   //here, pa->act() will act on a dangling reference. 
}

If your foo function just use the string, but doesn't retain references for later use, passing a temporary is perfectly safe.

If this happens using a "boot function" or a default temporary value makes no difference for the resulting code.

At that point using one or two function is much more a matter of style and opportunity: how many chances are for the two functions to differentiate during further development?

If the answer is "none: the second function is just THE definition (or a shortcut) for a very frequent case" than default value does perfectly the job.

If the answer is "let's fall back to the other function BY NOW, and later be more specific" then two function are preferrable.

Default values, are however NOT the chance in case the function are templates, and you want type deduction to work:

template<class C, class T>
void fn(int i, basic_string<C,T>& s = ????);

you cannot use std::string() since it wont work for C other than char, and cannot use std::basic_string<C,T>() since it will not allow to deduce, upon a fn(5) call to know what C and T should be.

So you will end-up with

void fn(int i) { fn(i,string()); }

.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top