【问题标题】:Is it a good practice to use temporary objects as arguments when overloading functions?重载函数时使用临时对象作为参数是一种好习惯吗?
【发布时间】:2014-01-05 08:29:13
【问题描述】:

给定原型:

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

实施:

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

    //  nothing more.

      }
//!   ^  here?

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

std::string() 创建的临时对象在哪里超出范围?以这种方式重载函数是一种好习惯吗?

更新:

让我稍微解释一下情况。作为练习,我正在尝试在不使用模板的情况下编写类似std::vector 的类。它拥有的唯一类型是std::string。类主体可以在another question中找到。

在实现resize()成员函数时,我发现std::vector似乎在使用两个函数:

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

所以我想知道是否应该使用两个函数而不是一个函数。

【问题讨论】:

  • 如果不理解预期的语义,真的不可能给出一个好的答案。如果两个foo 都做了同样的事情,给它们起相同的名字是有意义的,为什么需要更少参数的那个需要调用那个需要更多然后做更多事情的那个?这些东西是微不足道的(日志记录?)还是界面的可见部分,以至于一个 foo 做了一些外部理解为与另一个不同的事情?
  • 随着编辑,关于生命周期的问题没有多大意义。
  • @DavidSchwartz 嗨,我已经更新了帖子。希望它能让情况更清楚。

标签: c++ object-lifetime


【解决方案1】:

不,这不是一个好习惯,至少在这种特殊情况下是这样。使用单个函数和参数的默认值,而不是两个函数,其中一个似乎只是为了提供默认参数而存在:

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

【讨论】:

  • 在这种情况下似乎确实如此。
  • 你可能想说std::string()而不是"",以防万一实现为空文字分配内存。
  • @meagar 你好!我已经更新了线程。希望它能让情况更清楚。
  • 我同意他不需要重载,但如果提供默认参数,此解决方案中仍然存在临时对象。
【解决方案2】:

我不认为这是一种不好的做法,尤其是如果您将 foo(int i) 内联。我可以想到一个首选的原因:当您创建指向函数的指针时,如果您声明第二个参数默认值,您只能拥有指向接受 2 个参数的函数的指针。

临时值仅作为函数调用的参数才有效。

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

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

【讨论】:

  • 为什么要内联呢?让它更快?
【解决方案3】:

如果函数创建了一个对象,该对象在函数调用本身中存在,该对象本身存储了一个const&,则将临时值作为const& 传递的唯一“危险”。

想想

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. 
}

如果您的 foo 函数只是使用字符串,但不保留引用以供以后使用,则传递临时值是非常安全的。

如果发生这种情况,使用“引导函数”或默认临时值对生成的代码没有影响。

此时使用一个或两个函数更多的是风格和机会问题:这两个函数在进一步开发过程中有多少机会区分?

如果答案是“无:第二个函数只是非常常见情况的定义(或快捷方式)”,那么默认值就可以完美地完成这项工作。

如果答案是“让我们现在回退到另一个函数,然后再具体一点”,那么最好使用两个函数。

如果函数是模板,并且您希望类型推导起作用,则默认值是不可能的:

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

你不能使用 std::string() 因为它不适用于C 除了char,并且不能使用std::basic_string&lt;C,T&gt;() 因为它不允许推断,在fn(5) 调用知道什么C T 应该是。

所以你最终会得到

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

.

【讨论】:

    猜你喜欢
    • 2011-03-06
    • 2014-04-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-18
    • 2017-10-11
    • 1970-01-01
    • 1970-01-01
    • 2020-04-24
    相关资源
    最近更新 更多