定位C ++ 03时使用std :: basic_string <t>作为连续缓冲区是否合理?

我知道在C ++ 03中,从技术上说, std::basic_string模板不需要具有连续的内存。 不过,我很好奇现代编译器有多less实现可以利用这个自由。 例如,如果想要使用basic_string来接收一些C API的结果(比如下面的例子),那么分配一个向量直接把它变成一个string似乎很愚蠢。

例:

 DWORD valueLength = 0; DWORD type; LONG errorCheck = RegQueryValueExW( hWin32, value.c_str(), NULL, &type, NULL, &valueLength); if (errorCheck != ERROR_SUCCESS) WindowsApiException::Throw(errorCheck); else if (valueLength == 0) return std::wstring(); std::wstring buffer; do { buffer.resize(valueLength/sizeof(wchar_t)); errorCheck = RegQueryValueExW( hWin32, value.c_str(), NULL, &type, &buffer[0], &valueLength); } while (errorCheck == ERROR_MORE_DATA); if (errorCheck != ERROR_SUCCESS) WindowsApiException::Throw(errorCheck); return buffer; 

我知道这样的代码可能会稍微降低可移植性,因为它意味着std::wstring是连续的 – 但我想知道如何不可移植,使这个代码。 换句话说,编译器如何才能真正利用非连续内存的自由呢?


编辑:我更新了这个问题提到C + + 03。 读者应该注意的是,当针对C ++ 11时,标准现在要求basic_string是连续的,所以当针对该标准时上述问题不是问题。

我认为这是相当安全的假设std :: string连续分配其存储。

目前,所有已知的std::string实现都是连续分配空间的。

此外,C ++ 0x( N3000 )[编辑:警告,直接链接到大型PDF]的当前草案要求空间连续分配(§21.4.1/ 5):

basic_string对象中的char类对象应连续存储。 也就是说,对于任何basic_string对象,标识&*(s.begin()+ n)==&* s.begin()+ n应该适用于n的所有值,使得0 <= n <s.size ()。

因此,当前或未来使用非连续存储实现std::string的机会基本上是零。

前一段时间有一个关于能够写入std::string的存储的问题,就好像它是一个字符数组一样,它取决于std::string的内容是否是连续的:

  • 写入std :: string是否合法?

我的回答表明,根据一些好评的来源(Herb Sutter和Matt Austern),当前的C ++标准确实要求std::string在某些条件下保存它的数据(一旦你调用str[0]假设strstd::string ),这个事实几乎迫使任何实现的手。

基本上,如果将string::data()string::operator[]()所做的承诺组合在一起,那么可以得出结论: &str[0]需要返回一个连续的缓冲区。 所以Austernbuild议委员会只是明确地表明,这显然是在0x标准中发生的事情(或者他们现在称之为1x标准?)。

所以严格来说,一个实现不需要使用连续存储来实现std::string ,但是它必须在需求上做到这一点。 而你的示例代码通过传入&buffer[0]做到这一点。

链接:

  • 香草萨特的评论
  • 马特Austern的C ++标准库缺陷报告
  • 以前的答案

结果是不确定的,我不会这样做。 读入vector然后转换成string的代价在现代c ++堆中是微不足道的。 VS你的代码将在Windows 9中死亡的风险

此外,不需要一个const_cast on&buffer [0]?

编辑:你想调用&buffer[0]而不是 buffer.data() ,因为[]返回一个非const引用, 通知对象,它的内容可以意外改变。


执行buffer.data()会更干净,但是您应该比结构之间共享的内存less担心连续的内存。 string实现可以并且期望在对象被修改时被告知。 string::data特别要求程序不要修改返回的内部缓冲区。

除非长度设置为10或其他任何值,否则某些实现将为所有未初始化的string创build一个缓冲区的机会非常高。

new[] / delete[]使用一个vector甚至是一个数组。 如果你真的不能复制缓冲区,在改变它之前合法地将string初始化为唯一的东西。

当然,在这里分配一个向量是愚蠢的。 在这里使用std :: wstring也是不明智的。 最好使用char数组来调用winapi。 返回值时构造一个wstring。