[C/C++]_[初级]_[关于std::string的compare陷阱]

本文揭示了std::string的compare方法在比较字符串时可能存在的问题。由于compare会对比size()范围内的所有字节,包括''字符,这可能导致意外的结果。建议在不确定std::string内容是否为纯字符串时,先将其转换为const char*再用strcmp进行比较,以避免潜在错误。

场景

1.std::string 我们经常用来存储字符串数据, 当然它也可以作为byte的存储器,存储任意字节.

2.通常情况下我们使用 std::string 的 compare 方法比较字符串, 但这个方法比较奥字符串是不可靠的.

说明

1.compare 方法和 strcmp并不相同, 它比较的是 std::string size()大小里的所有字节.在size() 长度范围里, 如果有’\0’字符, 一样进行比较, 所有在不知道 std::string里是否存储纯字符串时, 最好先转换为 const char* (调用c_str()), 再调用 strcmp比较. 这个坑还是很吓人的.

例子

1.以下例子很好的说明在比较字符串时 compare并不适合.

#include <string>
#include <iostream>
#include <string.h>

int main(int argc, char
In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33, from /usr/include/c++/8/bits/allocator.h:46, from /usr/include/c++/8/string:41, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/ext/new_allocator.h: In instantiation of 'void __gnu_cxx::new_allocator<_Tp>::construct(_Up*, _Args&& ...) [with _Up = std::__cxx11::basic_string<char>; _Args = {const char&}; _Tp = std::_Rb_tree_node<std::__cxx11::basic_string<char> >]': /usr/include/c++/8/bits/alloc_traits.h:475:4: required from 'static void std::allocator_traits<std::allocator<_CharT> >::construct(std::allocator_traits<std::allocator<_CharT> >::allocator_type&, _Up*, _Args&& ...) [with _Up = std::__cxx11::basic_string<char>; _Args = {const char&}; _Tp = std::_Rb_tree_node<std::__cxx11::basic_string<char> >; std::allocator_traits<std::allocator<_CharT> >::allocator_type = std::allocator<std::_Rb_tree_node<std::__cxx11::basic_string<char> > >]' /usr/include/c++/8/bits/stl_tree.h:626:32: required from 'void std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_construct_node(std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type, _Args&& ...) [with _Args = {const char&}; _Key = std::__cxx11::basic_string<char>; _Val = std::__cxx11::basic_string<char>; _KeyOfValue = std::_Identity<std::__cxx11::basic_string<char> >; _Compare = Compare; _Alloc = std::allocator<std::__cxx11::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::__cxx11::basic_string<char> >*]' /usr/include/c++/8/bits/stl_tree.h:643:4: required from 'std::_Rb_tree_node<_Val>* std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_create_node(_Args&& ...) [with _Args = {const char&}; _Key = std::__cxx11::basic_string<char>; _Val = std::__cxx11::basic_string<char>; _KeyOfValue = std::_Identity<std::__cxx11::basic_string<char> >; _Compare = Compare; _Alloc = std::allocator<std::__cxx11::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_Link_type = std::_Rb_tree_node<std::__cxx11::basic_string<char> >*]' /usr/include/c++/8/bits/stl_tree.h:2400:13: required from 'std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::_M_emplace_equal(_Args&& ...) [with _Args = {const char&}; _Key = std::__cxx11::basic_string<char>; _Val = std::__cxx11::basic_string<char>; _KeyOfValue = std::_Identity<std::__cxx11::basic_string<char> >; _Compare = Compare; _Alloc = std::allocator<std::__cxx11::basic_string<char> >; std::_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator = std::_Rb_tree_iterator<std::__cxx11::basic_string<char> >]' /usr/include/c++/8/bits/stl_multiset.h:458:63: required from 'std::multiset<_Key, _Compare, _Alloc>::iterator std::multiset<_Key, _Compare, _Alloc>::emplace(_Args&& ...) [with _Args = {const char&}; _Key = std::__cxx11::basic_string<char>; _Compare = Compare; _Alloc = std::allocator<std::__cxx11::basic_string<char> >; std::multiset<_Key, _Compare, _Alloc>::iterator = std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >]' solution.cpp:34:43: required from here /usr/include/c++/8/ext/new_allocator.h:136:4: error: no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char&)' { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/8/string:52, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/bits/basic_string.h:649:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::__sv_wrapper, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(__sv_wrapper __svw, const _Alloc& __a) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:649:7: note: candidate expects 2 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:639:2: note: candidate: 'template<class _Tp, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Tp&, const _Alloc&)' basic_string(const _Tp& __t, const _Alloc& __a = _Alloc()) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:639:2: note: template argument deduction/substitution failed: /usr/include/c++/8/bits/basic_string.h:628:2: note: candidate: 'template<class _Tp, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Tp&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&)' basic_string(const _Tp& __t, size_type __pos, size_type __n, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:628:2: note: template argument deduction/substitution failed: In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33, from /usr/include/c++/8/bits/allocator.h:46, from /usr/include/c++/8/string:41, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/ext/new_allocator.h:136:4: note: candidate expects 4 arguments, 1 provided { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/8/string:52, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/bits/basic_string.h:614:9: note: candidate: 'template<class _InputIterator, class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(_InputIterator, _InputIterator, const _Alloc&)' basic_string(_InputIterator __beg, _InputIterator __end, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:614:9: note: template argument deduction/substitution failed: In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33, from /usr/include/c++/8/bits/allocator.h:46, from /usr/include/c++/8/string:41, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/ext/new_allocator.h:136:4: note: candidate expects 3 arguments, 1 provided { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/8/string:52, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/bits/basic_string.h:576:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(basic_string&& __str, const _Alloc& __a) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:576:7: note: candidate expects 2 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:572:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(const basic_string& __str, const _Alloc& __a) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:572:7: note: candidate expects 2 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:568:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::initializer_list<_Tp>, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(initializer_list<_CharT> __l, const _Alloc& __a = _Alloc()) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:568:7: note: no known conversion for argument 1 from 'const char' to 'std::initializer_list<char>' /usr/include/c++/8/bits/basic_string.h:541:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(basic_string&& __str) noexcept ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:541:7: note: no known conversion for argument 1 from 'const char' to 'std::__cxx11::basic_string<char>&&' /usr/include/c++/8/bits/basic_string.h:529:7: note: candidate: 'template<class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, _CharT, const _Alloc&)' basic_string(size_type __n, _CharT __c, const _Alloc& __a = _Alloc()) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:529:7: note: template argument deduction/substitution failed: In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33, from /usr/include/c++/8/bits/allocator.h:46, from /usr/include/c++/8/string:41, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/ext/new_allocator.h:136:4: note: candidate expects 3 arguments, 1 provided { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/8/string:52, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/bits/basic_string.h:514:7: note: candidate: 'template<class> std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&)' basic_string(const _CharT* __s, const _Alloc& __a = _Alloc()) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:514:7: note: template argument deduction/substitution failed: In file included from /usr/include/x86_64-linux-gnu/c++/8/bits/c++allocator.h:33, from /usr/include/c++/8/bits/allocator.h:46, from /usr/include/c++/8/string:41, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/ext/new_allocator.h:136:4: note: cannot convert 'std::forward<const char&>((* & __args#0))' (type 'const char') to type 'const char*' { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from /usr/include/c++/8/string:52, from /usr/include/c++/8/bits/locale_classes.h:40, from /usr/include/c++/8/bits/ios_base.h:41, from /usr/include/c++/8/ios:42, from main.cpp:7: /usr/include/c++/8/bits/basic_string.h:499:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]' basic_string(const _CharT* __s, size_type __n, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:499:7: note: candidate expects 3 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:481:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]' basic_string(const basic_string& __str, size_type __pos, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:481:7: note: candidate expects 4 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:465:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]' basic_string(const basic_string& __str, size_type __pos, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:465:7: note: candidate expects 3 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:450:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&, std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>; std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::size_type = long unsigned int]' basic_string(const basic_string& __str, size_type __pos, ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:450:7: note: candidate expects 3 arguments, 1 provided /usr/include/c++/8/bits/basic_string.h:437:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::__cxx11::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(const basic_string& __str) ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:437:7: note: no known conversion for argument 1 from 'const char' to 'const std::__cxx11::basic_string<char>&' /usr/include/c++/8/bits/basic_string.h:429:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string(const _Alloc& __a) _GLIBCXX_NOEXCEPT ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:429:7: note: no known conversion for argument 1 from 'const char' to 'const std::allocator<char>&' /usr/include/c++/8/bits/basic_string.h:420:7: note: candidate: 'std::__cxx11::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]' basic_string() ^~~~~~~~~~~~ /usr/include/c++/8/bits/basic_string.h:420:7: note: candidate expects 0 arguments, 1 provided什么错误
06-07
### C++ 编译错误 'no matching function for call to 'std::__cxx11::basic_string<char>::basic_string(const char&)' 的解决方案 此错误表明尝试以不兼容的方式初始化或构造 `std::string` 对象。具体来说,编译器无法找到与传递的参数类型匹配的 `std::string` 构造函数[^3]。 #### 错误原因分析 `std::string` 的构造函数并不接受单个 `const char&` 类型的参数。通常,这种错误可能出现在以下场景中: - 尝试将单个字符(`char`)直接传递给 `std::string` 构造函数。 - 在容器操作(如 `std::vector` 或 `std::multiset` 的插入操作)中,错误地传递了不兼容的类型。 例如,以下代码会导致上述错误: ```cpp #include <string> #include <iostream> int main() { char c = 'a'; std::string str(c); // 错误:没有匹配的构造函数 std::cout << str << std::endl; return 0; } ``` #### 解决方案 为了正确初始化 `std::string`,可以使用以下方法之一: 1. **显式构造包含单个字符的字符串**: 如果需要从单个字符创建字符串,应使用 `std::string` 的重复构造函数,指定字符数量为 1: ```cpp #include <string> #include <iostream> int main() { char c = 'a'; std::string str(1, c); // 正确:构造包含单个字符的字符串 std::cout << str << std::endl; return 0; } ``` 2. **避免传递不兼容的类型**: 如果在容器操作中出现此问题,确保传递正确的类型。例如,在向 `std::multiset<std::string>` 插入元素时,应传递 `std::string` 而非 `char`: ```cpp #include <set> #include <string> #include <iostream> int main() { std::multiset<std::string> ms; char c = 'a'; ms.emplace(std::string(1, c)); // 正确:构造字符串后再插入 for (const auto& s : ms) { std::cout << s << std::endl; } return 0; } ``` 3. **检查模板推导问题**: 在某些情况下,模板参数推导可能导致错误。例如,如果在模板函数中隐式推导类型,可能会导致不匹配。可以通过显式指定类型来解决: ```cpp template <typename T> void addString(T&& value) { std::string str = std::forward<T>(value); std::cout << str << std::endl; } int main() { char c = 'a'; addString(std::string(1, c)); // 正确:显式构造字符串 return 0; } ``` #### 示例代码 以下是一个综合示例,展示了如何避免此类错误并正确使用 `std::string` 构造函数: ```cpp #include <string> #include <set> #include <iostream> int main() { char c = 'a'; // 错误用法 // std::string str(c); // 错误:没有匹配的构造函数 // 正确用法 std::string str1(1, c); // 构造包含单个字符的字符串 std::multiset<std::string> ms; ms.emplace(str1); // 插入正确构造的字符串 // 输出结果 for (const auto& s : ms) { std::cout << s << std::endl; } return 0; } ``` #### 注意事项 - 在使用 `std::string` 构造函数时,确保传递的参数类型与构造函数签名匹配。 - 如果需要从单个字符创建字符串,建议使用 `std::string(1, char)` 的形式。 - 在容器操作中,确保插入的元素类型与容器存储的类型一致。 --- ###
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白行峰 (花名)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值