std::string s1 "现代 C++", 3 与 std::string s1 str, 3
Posted
技术标签:
【中文标题】std::string s1 "现代 C++", 3 与 std::string s1 str, 3【英文标题】:std::string s1 "Modern C++", 3 vs std::string s1 str, 3std::string s1 "现代 C++", 3 与 std::string s1 str, 3 【发布时间】:2021-01-01 22:35:30 【问题描述】:以下代码的输出让我感到困惑:
const std::string str = "Modern C++";
std::string s1 "Modern C++", 3;
std::string s2 str, 3;
std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";
输出:
> S1: Mod
> S2: ern C++
谁能解释一下这个结果?
【问题讨论】:
你在std::string
构造函数上读过the reference吗? "Modern C++"
不是 std::string
而是一个字符数组(它会自动转换为 char 指针),并且有一个不同的构造函数。
当然。参考资料会告诉你。而且我敢肯定,它们不做同样的事情有一些非常聪明的原因,C++ 库委员会会用无可挑剔的逻辑和推理向我证明这一点。然而,这只是 C++ 标准库使用起来仍然不直观,甚至令人沮丧的另一个原因(尽管很小)。
@HolyBlackCat 不过,结果应该是一样的,谢谢。
“非常聪明的原因”是 std::string 最初是在几十年前设计的,所以事后看来,它的一些构造函数和函数不适合我们认为的现代直观界面跨度>
@M.M.:再加上 C 风格的字符串是在更早之前设计的,std::string
必须遵守他们的约定。也就是说,可能应该对两者都坚持相同的 C 风格字符串语义,而不是将位置作为 std::string
的有效起点和 char *
的有效终点,所以你的观点仍然成立,只是指出这个领域的兼容性限制甚至早于std::string
。
【参考方案1】:
发件人:
https://en.cppreference.com/w/cpp/string/basic_string/basic_string
std::string s1 "Modern C++", 3;
使用以下构造函数:
basic_string( const CharT* s,
size_type count,
const Allocator& alloc = Allocator() );
所以需要 3 个字符才能得到 Mod
。
std::string s2 str, 3;
将使用以下构造函数:
basic_string( const basic_string& other,
size_type pos,
const Allocator& alloc = Allocator() );
因此,从位置 3 开始获取字符串:ern C++
。
【讨论】:
谢谢。第一个是size_type count
,第二个是size_type pos
。
人们不得不问他们为什么要添加两个具有如此不同行为的构造函数。就像是不假思索地拼凑起来的。
@Polygnome:“完全没有思想的拼凑”基本上描述了整个std::string
。它还解释了基于索引和基于迭代器的方法的混合——字符串是独立于 STL 开发的,然后进行了追溯扩充以匹配——并且通常有太多的“方便方法。我总是喜欢 GOTW #84: Monoliths Unstrung 潜水变成一个由免费函数补充的最小字符串 API。
这个子字符串构造函数是否有一个用例不能由substr
方法提供服务?【参考方案2】:
一个打电话给string(char const*, count)
,另一个打电话给string(string const&, pos)
。
一个从缓冲区中获取前 3 个字符,另一个从第 3 个字符之后获取所有字符。
这是因为 C++ 有原始字符缓冲区和标准字符串。 "this is not a std::string"
。 "this is a std string"s
, std::string so_is="this";
.
std::string
已经有 30 多年的历史了,它被添加到 C++ 语言中时没有得到足够的照顾(不像 STL,它在添加之前经历了更多的迭代)。
它的界面实在是太丰富了,你可以碰到这样的东西;导致混淆结果的多个重载。
【讨论】:
【参考方案3】:谁能给我解释一下这是为什么?
这是由于 std::string
具有它确实不应该的构造函数(@ORR explained 详细信息)。它不应该有这些构造函数,因为:
-
使用named constructor idioms /
std::string
方法和现有构造函数可以轻松实现它们的效果 - 无需额外成本(至少在 C++11 中),并且
仅通过查看构造函数调用来理解构造函数参数的使用方式并不明显和微不足道。
这不是标准库中唯一具有这种不受欢迎(恕我直言)构造函数的情况; std::vector
以 too much constructor variety 和令人困惑/误导的构造函数语义而闻名。
人生教训:
在构造函数上省钱;并非所有用于构造类对象的常用值都值得拥有自己的构造函数; 改为使用named constructor idioms。 让您的代码审查员或其他一些不偏不倚的人阅读您的构造函数的调用,以判断每个构造函数的含义是否足够明显。【讨论】:
【参考方案4】:如果您想获得相同的输出,例如
Mod for s1
Mod for s2
您可以使用字符指针作为 str 例如
char * str = "Modern C++";
std::string s1 "Modern C++", 3;
std::string s2 str, 3;
std::cout << "S1: " << s1 << "\n";
std::cout << "S2: " << s2 << "\n";
输出
Mod
Mod
【讨论】:
为了让它工作,第一行应该是:char str[] = "Modern C++";或 char str[] "现代 C++"; 试试看,对我来说效果很好。在 c++/c 中,您还可以使用指针声明和初始化字符数组。 char * str = "现代 C++" ;使用 str[value] 循环,因为 str 现在是一个数组。 我相信没有 [ ] 的语法是 char ** str。 具有讽刺意味的是,char * str = "Modern C++";
是无效的现代 C++。从 C++11 开始需要 const。 wandbox.org/permlink/e3TA4tKbrkBOOUll (gcc) / wandbox.org/permlink/TFTRyB565SVyhMlb (clang)以上是关于std::string s1 "现代 C++", 3 与 std::string s1 str, 3的主要内容,如果未能解决你的问题,请参考以下文章
将 std::string 转换为 std::wstring 时,C++17 codecvt 抛出“错误转换”