vic*_*ict 5 c++ std stdstring string-view c++20
我想知道如何正确处理函数中的字符串输入,如果我知道我将必须在其中创建一个副本以将其放入容器中。
我想这样做:
void foo(const string& s){
container.push(s);
}
Run Code Online (Sandbox Code Playgroud)
但是如果我传递一个 char* 字符串,我将制作 2 个副本,首先是在调用 foo 时,然后是在将其传递到容器时。
我的第二个想法是使用 string_view,正如人们常说的,如果你可以使用视图,你就应该使用。所以我的函数的第二个版本如下所示:
void foo2(string_view s){
container.push(string(s));
}
Run Code Online (Sandbox Code Playgroud)
好的,现在无论给我什么类型的字符串,我都会只制作一个副本。但后来我开始思考,为什么我不能接受一个字符串作为函数的参数,像这样简化它:
void foo3(string s){
container.push(std::move(s));
}
Run Code Online (Sandbox Code Playgroud)
但现在我必须确保我的容器正确利用移动语义,这样它最终不会制作另一个副本!由于此容器对象是模板化类型,因此意味着使用完美转发等,这本身就是大量工作。
目前我不知道该选择哪个选项,所以想请教您一些建议。我还觉得我想得太多了,因为这最终可能不会对性能产生太大影响,但我想做得正确。提前致谢。
你知道你std::string最终肯定需要一个。不是类似字符串的东西,而是一个std::string. 在这种情况下,将 以外的任何东西作为参数是没有意义的std::string。也有例外,例如,如果您使用所有公开的接口,std::string_view那么在这里这样做也可能有意义。
现在的选择是const std::string&(左值引用)、std::string&&(右值引用)和std::string(值)。在这种情况下,您知道需要一个新对象传递到低于推荐对象的级别:value +std::move。
这边走:
std::string您将获得 1 次转化 + 1 次移动std::string您将获得 1 个副本 + 1 个移动(如果用户std::move在呼叫站点这样做,则为 1 个移动 + 1 个移动)。但现在我必须确保我的容器正确利用移动语义
不,不是“现在”。这不应该是您开始考虑容器移动语义的点。容器很可能应该具有适当的移动语义,只是因为它是……嗯,容器。当您可以移动 5k 元素时,您不想复制它们。
第四个选项是使用完美转发并将参数按foo 原样传递给容器的emplace/emplace_back函数:
template<class... Args>
requires std::constructible_from<std::string, Args...>
void foo4(Args&&... args){ // a forwarding reference pack
container.emplace(std::forward<Args>(args)...);
}
Run Code Online (Sandbox Code Playgroud)
std::string给foo4,它将使用std::string移动构造函数。没有其他的。foo4,它将使用std::string复制构造函数。没有其他的。std::string(例如 a )std::string_view,它将在容器中就地构造。甚至不需要复制或移动。通过手动创建避免不必要的实例化所需的重载,您可以同样出色地处理上述前两种情况。
void foo4(const std::string& f) { container.push(f); } // one copy
void foo4(std::string&& f) { container.push(std::move(f)); } // one move
Run Code Online (Sandbox Code Playgroud)
然而,第三种情况不会同样有效。如果您不关心或不想支持第三种情况,您可以选择两个重载来模仿复制构造函数/移动构造函数对的功能。既然您询问如何 “有效地传递字符串”,我认为添加重载是一个很小的代价。
| 归档时间: |
|
| 查看次数: |
313 次 |
| 最近记录: |