好的,我正在考虑以下C ++代码:
foo (std::string str) {
// do whatever
}
foo(const char *c_str) {
foo(std::string(c_str));
}
我看一下这段代码并认为它需要重写以通过引用传递。基本上,我担心构造函数将被调用两次,一次在const char *版本的foo中,并且当参数作为std :: string传递给foo时再次被调用,因为它被设置为通过副本传递。我的问题是:我是对的,还是g ++足够聪明,可以将构造函数放在c字符串版本中并称之为好?似乎g ++无法做到这一点,但我只是希望真正知道的人可以澄清它。
答案 0 :(得分:1)
理论上将涉及两个构造函数(一个用于创建临时文件,另外还有用于传递副本的复制构造函数);实际上,显式允许编译器执行复制省略(C ++11§12.8¶32)。
但是你不需要两个重载开始。
正常的方法是只拥有一个const std::string &
的函数版本。如果调用者已经有std::string
,则不执行任何复制,因为我们通过引用传递。如果它具有char *
,则创建临时std::string
(因为它具有来自const char*
的非显式构造函数)并传递给函数(因为const引用可以绑定到临时工)。
答案 1 :(得分:0)
你可以用惯用的方式写
foo (std::string const& str) {
// do whatever
}
不需要重载,因为你可以隐式构造一个临时的:
foo("yes");
如果您打算在某处存储参数的值,可以使用右值引用:
foo (std::string && str) {
my_member = std::move(str);
}
但是为了避免过载爆炸,按值获取参数通常是一个很好的中间点:
无论有关idomatic参数传递的所有这些好的服务,是的,编译器可以在as-if规则下优化掉虚假副本(尽管复制构造函数需要可访问,就好像复制完成)
答案 2 :(得分:0)
由于传递给foo
的临时名称未命名,因此直接构造参数,消除副本似乎是一个相当简单的优化,尽管标准不保证这一点(因为没有优化是)。
更一般地说,你应该通过常量引用,除非你的函数已经获取参数本身的副本(例如,可能复制和变异),