【问题标题】:Is this way of using std::string safe?这种使用 std::string 的方式安全吗?
【发布时间】:2015-05-29 08:23:50
【问题描述】:

我正在编写一个字符串类(Utf8String),它包装(具有)一个 std::string(因为它很方便)。

出于某种原因,我必须访问包装的 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。

【问题讨论】:

  • 您对reserveresize 的使用没有任何合法性。超出字符串的 size 的写入具有未定义的行为,无论容量如何。
  • 你是否在一个返回char *的函数中声明return m_sBuf.c_str();,甚至编译
  • @KerrekSB 我知道这不是使用 std::string 的正确方法,这就是我问的原因,因为我怀疑会有问题。如果我使用调整大小而不是保留怎么办? WhozCraig 我为这个问题编写了这段代码,我只是忘记了 const_cast,但这并不是重点。

标签: c++ string stl


【解决方案1】:

来自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 中的内存。

【讨论】:

  • 如果只需要 nRealLen 的数量,那么结果 sMessage 不是由 buffer 的所有 1024 个字符构建的会更好。
  • 可能。我在 OP 的问题中保留了该代码,并在我的回答中专注于字符串滥用。
  • 感谢您的回答。我想过做类似的事情,通过使用 new 创建一个 char 缓冲区,并将这个缓冲区分配给字符串(例如),但我的老板不喜欢它,他想要类似于 CString::GetBuffer()、CString ::Release() 来自 MFC,这就是我在问题中提出设计的原因。除了 std::array 是 C++,我不能使用。
  • @Virus721 无论他“喜欢”与否,都不再正确。调用未定义的行为是灾难的根源,我只祈祷你构建的任何东西,他管理的不是关键任务。做对了。如果需要,重构您的代码并适当地管理 std::vector&lt;char&gt;
  • 特别是 CString::GetBufferCString::Release 模型很糟糕 - 非常非常糟糕:它是一个依赖于正确编写客户端代码的接口(只是不要!),并询问您了解底层实现(不不不!)。如果您没有正确使用这两个 API,应用程序就会静默损坏。
猜你喜欢
  • 2012-09-01
  • 1970-01-01
  • 2011-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-09
  • 1970-01-01
  • 2011-01-14
相关资源
最近更新 更多