使用http://en.cppreference.com/w/cpp/string/basic_string_view作为参考,我认为没有办法更优雅地做到这一点:
std::string s = "hello world!";
std::string_view v = s;
v = v.substr(6, 5); // "world"
更糟糕的是,天真的做法是一个陷阱,让v
悬挂在一个临时的引用上:
std::string s = "hello world!";
std::string_view v(s.substr(6, 5)); // OOPS!
我似乎记得这样的东西可能会增加标准库以返回子字符串作为视图:
auto v(s.substr_view(6, 5));
我可以想到以下解决方法:
std::string_view(s).substr(6, 5);
std::string_view(s.data()+6, 5);
// or even "worse":
std::string_view(s).remove_prefix(6).remove_suffix(1);
坦率地说,我认为这些都不是很好。现在我能想到的最好的事情就是使用别名来简化事情。
using sv = std::string_view;
sv(s).substr(6, 5);
答案 0 :(得分:36)
有自由功能路线,但除非你也为std::string
提供过载,否则它就是一个蛇坑。
#include <string>
#include <string_view>
std::string_view sub_string(
std::string_view s,
std::size_t p,
std::size_t n = std::string_view::npos)
{
return s.substr(p, n);
}
int main()
{
using namespace std::literals;
auto source = "foobar"s;
// this is fine and elegant...
auto bar = sub_string(source, 3);
// but uh-oh...
bar = sub_string("foobar"s, 3);
}
恕我直言,string_view的整个设计是一个恐怖表演,它将带我们回到段落错误和愤怒的客户世界。
即使为std::string
添加重载也是一个恐怖节目。看看你是否能发现微妙的段错定时炸弹...
#include <string>
#include <string_view>
std::string_view sub_string(std::string_view s,
std::size_t p,
std::size_t n = std::string_view::npos)
{
return s.substr(p, n);
}
std::string sub_string(std::string&& s,
std::size_t p,
std::size_t n = std::string::npos)
{
return s.substr(p, n);
}
std::string sub_string(std::string const& s,
std::size_t p,
std::size_t n = std::string::npos)
{
return s.substr(p, n);
}
int main()
{
using namespace std::literals;
auto source = "foobar"s;
auto bar = sub_string(std::string_view(source), 3);
// but uh-oh...
bar = sub_string("foobar"s, 3);
}
编译器在这里没有发现任何警告。我确信代码审查也不会。
之前我已经说过了,我会再说一遍,如果c ++委员会的任何人都在观看,允许从std::string
到std::string_view
的隐式转换是一个可怕的错误,只会使c ++变得声名鹊起。
在cpporg留言板上提出了这个(对我而言)相当惊人的string_view属性,我的担忧已经得到了冷漠。
这个小组的建议的共识是std::string_view
绝不能从函数返回,这意味着我上面的第一个提供是不好的形式。
当然偶然发生这种情况时(例如通过模板扩展),没有编译器帮助来捕获时间。
因此,应该非常小心地使用std::string_view
,因为从内存管理的角度来看,它等同于指向另一个对象状态的可复制指针,该对象可能不再存在。但是,它在所有其他方面看起来和行为都像值类型。
因此这样的代码:
auto s = get_something().get_suffix();
get_suffix()
返回std::string
(按值或参考)
但如果get_suffix()被重构为返回std::string_view
,则为UB。
在我的简略视图中,这意味着,如果他们调用的库被重构为返回auto
代替std::string_view
,那么使用std::string const&
存储返回字符串的任何用户代码都将中断。
所以从现在开始,至少对我来说,“几乎总是自动”必须变成“几乎总是自动的,除非它是字符串”。
答案 1 :(得分:3)
您可以使用 std :: string 中的转换运算符到 std :: string_view :
std::string s = "hello world!";
std::string_view v = std::string_view(s).substr(6, 5);
答案 2 :(得分:0)
这是有效地创建子字符串string_view的方法。
#include <string>
inline
std::string_view substr_view(const std::string &s,size_t from,size_t len) {
if( from>=s.size() ) return {};
return std::string_view(s.data()+from,std::min(s.size()-from,len));
}
#include <iostream>
int main(void) {
std::cout << substr_view("abcd",3,11) << "\n";
std::string s {"0123456789"};
std::cout << substr_view(s,3,2) << "\n";
return 0;
}