我正在使用 C 例程写入 std::string 的数据字段。这是一个人为的示例,实际上我通过网络获取一个非空终止的字符串及其大小:
#include <string>
#include <cstdio>
#include <cstring>
const char* str = "Some examplory string..";
int main()
{
std::string some_str;
some_str.resize(strlen(str));
std::strcpy(&some_str.front(), str);
printf(some_str.c_str());
}
现在根据 cppref ,
resize()
没有重载,它只是调整大小并且不会用 ' ' 或其他东西初始化内存。但如果我所做的只是再次覆盖它,为什么我要为此付费呢?可以通过某种方式避免这种情况吗?
对于 c++23,我们有 resize_and_overwrite
对于旧标准,让我们破解它!
它在 gcc5+、clang12+、msvc 1921+ 上运行良好
// Our hacker function, resize a std::string without initializing memory
// (but still has '\0' in the end of string)
inline void resize(std::string& str, std::size_t sz);
#if __cpp_lib_string_resize_and_overwrite >= 202110L
inline void resize(std::string& str, std::size_t sz) {
str.resize_and_overwrite(sz, [](char*, std::size_t sz) {
return sz;
});
}
#elif (defined(__clang_major__) && __clang_major__ <= 11) ||(defined(_MSC_VER)&& _MSC_VER<=1920)
// old clang has bug in global friend function. discard it.
// old msvc don't support visit private, discard it.
inline void resize(std::string& str, std::size_t sz) { str.resize(sz); }
#else
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION)
template <typename Money_t, Money_t std::string::* p>
class string_thief {
public:
friend void string_set_length_hacker(std::string& bank, std::size_t sz) {
(bank.*p)(sz);
}
};
#elif defined(_MSVC_STL_VERSION)
template <typename Money_t, Money_t std::string::* p>
class string_thief {
public:
friend void string_set_length_hacker(std::string& bank, std::size_t sz) {
(bank.*p)._Myval2._Mysize = sz;
}
};
#endif
#if defined(__GLIBCXX__) // libstdc++
template class string_thief<void(std::string::size_type),
&std::string::_M_set_length>;
#elif defined(_LIBCPP_VERSION)
template class string_thief<void(std::string::size_type),
&std::string::__set_size>;
#elif defined(_MSVC_STL_VERSION)
template class string_thief<decltype(std::string::_Mypair),
&std::string::_Mypair>;
#endif
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \
defined(_MSVC_STL_VERSION)
void string_set_length_hacker(std::string& bank, std::size_t sz);
#endif
inline void resize(std::string& str, std::size_t sz) {
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \
defined(_MSVC_STL_VERSION)
str.reserve(sz);
string_set_length_hacker(str, sz);
str[sz] = '\0';
#else
str.resize(sz);
#endif
}
#endif