C++ 字符连接与 std::string 行为。请解释一下
Posted
技术标签:
【中文标题】C++ 字符连接与 std::string 行为。请解释一下【英文标题】:C++ character concatenation with std::string behavior. Please explain this 【发布时间】:2016-07-25 16:59:37 【问题描述】:这里有一些我无法理解的关于 c++ std::string 的案例。
1.
string ans = ""+'a';
cout << ans << endl; //Prints _string::copy
2.
string ans="";
ans=ans+'a';
cout << ans << endl; //Prints a
3.
string ans="";
ans = ans + (5 + '0'); // Throws error
4.
string ans="";
ans += (5 + '0'); //works
5.
在代码中,我有一行
ans += to_string(q);
q 是一位整数。程序抛出运行时错误。
将其更改为ans+= (q+'0');
,错误已被删除。
请帮助清除这个想法。
【问题讨论】:
""+'a'
将超出范围并调用未定义的行为。
如果q
是整数,ans += to_string(q);
应该可以正常工作。
如何超出范围?当 + 未重载时,向字符串添加字符是否有效?
""
不是std::string
,它是char
的数组,当您向其中添加整数类型时,您将对该数组的地址执行指针运算。这与串联非常不同。
你和其他人都不能重载两边都是基本类型的运算符。所以,""
是(衰减为)char const *`,'a'
是char
,这意味着您要将字符a
的ASCII 编号添加到该特定空字符串的地址...因此越界并调用UB。但是,如果您想要您错误预期的 std::string
文字,请执行 using namespace std::string_literals; auto wow = "a std::string"s
。
【参考方案1】:
string ans = ""+'a';
"" 是空字符串文字的地址。 'a' 被解释为整数,ASCII 码 65。这会将 65 添加到文字字符串的地址,这会导致未定义的行为,可能会导致崩溃。
ans=ans+'a';
ans
是一个std::string
。 std::string
定义了一个重载的 +
运算符。实际上有几个。其中之一,特别是重载+
,其中参数是一个字符,并将该字符附加到字符串中。
ans = ans + (5 + '0'); // Throws error
5+'0'
是提升为int
类型的表达式。 std::string
不会明确地将 +
运算符重载,并将 int
作为参数。这会导致编译错误。
ans += (5 + '0'); //works
std::string
确实有一个明确的重载 +=
运算符,所以编译得很好。
【讨论】:
在第 5 种情况下,5+'0'
也被提升为 int
。那么,它与第 4 种情况有何不同?
不同的运算符。 +
与 +=
,定义不同的重载。
好的,所以没有为 int 定义 +,而为 int 定义了 +=。知道了。谢谢。
不,+=
没有为 int
定义。它仅针对char
定义,但对于operator +=
没有其他可以将int
参数转换为的重载,因此没有歧义。
C++11 为使用移动语义的std::string
的右值引用添加了operator+
。带有int
的operator+
可以转换为采用char 参数的基于常规复制的operator+
,或者采用char 参数的基于移动的operator+
,因此会产生歧义。显然,operator+=
没有移动语义。【参考方案2】:
这个:
std::string ans = ""+'a';
不是你想的那样,你实际上执行的操作如下:
const char* p = "";
p = p + 97 /*97=='a'*/; // increase p pointer by `a` value, results in UB (pointer to random memory)
std::string ans = p; // p points to possibly unallocated memory (UB).
这没什么意义。
如果你用 clang 编译它,你会得到很长的警告列表:
main.cpp:22:25: warning: adding 'char' to a string does not append to the string [-Wstring-plus-int]
std::string ans = ""+'a';
~~^~~~
main.cpp:22:25: note: use array indexing to silence this warning
std::string ans = ""+'a';
^
& [ ]
main.cpp:22:25: warning: adding 'char' to a string pointer does not append to the string [-Wstring-plus-char]
std::string ans = ""+'a';
~~^~~~
main.cpp:22:25: note: use array indexing to silence this warning
std::string ans = ""+'a';
^
& [ ]
【讨论】:
【参考方案3】:字符串字面量是一个字符数组。它不是std::string
的实例。数组不能按值传递给函数或运算符,而是在使用操作数时衰减为指向第一个字符的指针。
字符是编码符号的数字。所有字符都有一个非零值,'\0'
除外。
在表达式""+'a'
中,字符串文字衰减为指针,然后'a'
字符被解释为非零整数。该值被添加到指针中。不管a
的值是多少(在常用的ASCII编码中恰好是65),结果都超出了数组的范围。超出范围的指针算术具有未定义的行为,输出 1. 是未定义行为的结果。
程序 2. 具有明确定义和预期的行为。
ans = ans + (5 + '0'); // Throws error
没有接受参数std::string
和int
的operator+
。右边的参数是int
,因为5 + '0'
中的char
参数被提升为int
,因此两个参数属于同一类型。这也是表达式的返回类型。
这是它变得毛茸茸的地方。有一个operator+
接受char
并且int
可以转换为char
。但是,还有其他可能的转换是模棱两可的。这是clang显示的错误:
error: invalid operands to binary expression ('string' (aka 'basic_string<char>') and 'int')
ans = ans + (5 + '0'); // Throws error
~~~ ^ ~~~~~~~~~
./include/c++/6.1.0/bits/basic_string.h:4982:5: note: candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'int')
operator+(const basic_string<_CharT, _Traits, _Alloc>& __lhs, _CharT __rhs)
^
./include/c++/6.1.0/bits/basic_string.h:5036:5: note: candidate template ignored: deduced conflicting types for parameter '_CharT' ('char' vs. 'int')
operator+(basic_string<_CharT, _Traits, _Alloc>&& __lhs,
^
...以及许多其他潜在的重载。
ans += (5 + '0'); //works
这是因为operator+=(char);
是一个明确的重载。
在代码中,我有一行 ans += to_string(q); q 是一位整数。程序抛出运行时错误。
Works fine here, no errors thrown.
【讨论】:
数组不能传递给函数或操作符 那么它们可以通过引用传递, @NathanOliver 资格已添加。以上是关于C++ 字符连接与 std::string 行为。请解释一下的主要内容,如果未能解决你的问题,请参考以下文章
GCC 如何连接多个 C++ std::string 变量?
奇怪的 C++ std::string 行为......我该如何解决这个问题?
C++ std::string::size()函数(返回字符串的长度,以字节为单位)(与std::string::length()函数相同)