定位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]
假设str
是std::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。