我正在编写一个包含(拥有)std :: string的字符串类(Utf8String)(因为它非常方便)。
由于某种原因,我必须访问包装的std :: string的内部缓冲区才能直接写入它。我知道这很脏,而且反对封装原则和所有这些,但我必须这样做。
让以下Utf8String类成员:
std::basic_string< char > m_sBuf;
inline char * Reserve( uint32_t nNewByteCap )
{
m_sBuf.reserve( nNewByteCap );
return const_cast< char * >( m_sBuf.c_str() );
}
inline void Resize( uint32_t nNewByteCount )
{
// Some stuff ...
m_sBuf.resize( nNewByteCount, ' ' );
}
为了做这样的事情:
Utf8String sMessage;
char * sBuffer = sMessage.Reserve( 1024 );
uint32_t nRealLen = some_c_function_write_to_buffer( sBuffer, sMessage.Capacity() );
sMessage.Resize( nRealLen );
我不确定STL如何在内部工作。据我所知,它接受在std :: string中间丢失空字符,因此在字符串的实际结尾之前放置一个空字符应该不是问题。
由于STL实现在不同平台上可能有所不同,因此对我的测试并不意味着它也适用于其他平台。
您是否在这段代码中看到了可以破坏我使用的std :: string对象的内容?谢谢你的帮助。
PS:我不能使用C ++ 11。
答案 0 :(得分:2)
来自http://en.cppreference.com/w/cpp/string/basic_string/c_str:
写入通过c_str()访问的字符数组是未定义的行为。 你不应该这样做。
更安全的代码:
Utf8String sMessage;
std::array<char, 1024> buffer;
uint32_t nRealLen = some_c_function_write_to_buffer( buffer.data(), buffer.size() );
sMessage.Assign(sBuffer.begin(), sBuffer.end());
最后一行假定您在字符串类中有:
template<typename InIt>
void Assign(InIt begin, InIt end) {
m_sBuf.assign(begin, end);
}
(或同等的)。
这样做更好,因为它不能访问c_str返回的数据,也不会尝试手动管理std :: string中的内存。