C++ 哪种重载组合最有效?

C++ 哪种重载组合最有效?,c++,string,performance,c++11,C++,String,Performance,C++11,我有这样一个函数: void init_str(std::string _s) { std::string s{_s}; } 我想通过允许constchar*重载来进行优化,以避免创建临时std::string void init_str(const char* c) { std::string s{c}; } 但我也可以使用转发 template<typename T> void init_str(T&& t) { std::string

我有这样一个函数:

void init_str(std::string _s)
{
    std::string s{_s};
}
我想通过允许
constchar*
重载来进行优化,以避免创建临时
std::string

void init_str(const char* c)
{
    std::string s{c};
}
但我也可以使用转发

template<typename T>
void init_str(T&& t)
{
    std::string s{std::forward<T>(t)};
}
模板
void init_str(T&T)
{
std::string s{std::forward(t)};
}
但是编译器对重载的偏好是:

  • const char*
  • 转发
  • std::string

那么我应该选择哪种重载组合呢?

假设使用c++11或更高版本,最有效的解决方案是您尚未尝试过的解决方案:

void init_str(std::string s)
{
  // just use s
}
因为复制省略将确保根本不构建任何不必要的临时文件

它使用std::string(const char*)构造函数构造s(总共1个构造):

这将使用复制构造函数构造s:

std::string x; // 1 constructor
init_str(x);   // 1 copy constructor
这将使用移动构造函数构造s

std::string x;            // 1 constuctor
init_str(std::move(x));   // 1 move constructor
这实际上根本不会创建临时文件:

std::string get_str() {
    std::string s("xxx");   // 1 constructor, but...
    return s;               // ...because of RVO it's constructed at the call site
}

init_str(get_str());        // ... which is actually the constructor of s in init_str's arg list
// ... total constructors: 1

首先考虑你的输入参数:

void init_str(std::string s)
{
    // use s here ...
}
无论调用什么函数,
std::string
构造函数都应该做最有效的事情

如果您使用临时命令调用,它将在中移动(
std::move()
)。如果使用
const char*
调用它,它将通过重载的
std::string()
构造函数有效地复制进来

因此,您无法真正提高创建参数字符串的效率

你的问题不清楚你想要的是两条线还是一条线。如果函数中需要两个字符串,则:

void init_str(std::string s1)
{
    std::string s2 = s1;

    // use s1 & s2 here ...
}
如果您想要参数字符串的副本,那么移动不是一个选项。让第二个字符串等于第一个字符串是最好的选择。
std::string
assignment操作符具有生成最有效副本所需的所有信息


我看不出您的其他解决方案在这方面有什么改进。

应该没有显著差异。如果你对这些东西有疑问,请测量。不管怎样,这个函数都会被完全优化。真正的答案将取决于真正的函数。我将遵循@πάνταῥεῖ 说
std::string_view
(TS)也可能是一个很好的解决方案(overkill?)。您的第一个示例逐副本接受字符串,然后制作另一个副本,表明您需要两个副本。但是您的
const char*
示例只剩下一个字符串。如果确实只需要一个字符串,那么第一个示例不需要将参数复制到第二个字符串。此外,它的构造函数应该根据传入的内容做出最佳选择,因为它具有移动语义。如果您只需要一根字符串,那么您可能无法获得比这更好的结果。只需通过复制接受参数,不要重新复制它。
t&&t
将根据作为参数传递的原始字符串文本的长度创建单独的函数模板专门化,除非您有
const char*c
重载
void init_str(std::string s1)
{
    std::string s2 = s1;

    // use s1 & s2 here ...
}