31

我知道在 C++03 中,从技术上讲,std::basic_string模板不需要具有连续的内存。但是,我很好奇实际上利用这种自由的现代编译器有多少实现。例如,如果想用来basic_string接收某个 C API 的结果(如下例所示),分配一个向量只是为了立即将其转换为字符串似乎很愚蠢。

例子:

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是连续的,因此在面向该标准时,上述问题不是问题。

4

5 回答 5

25

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

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

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

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

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

于 2010-02-13T02:08:34.920 回答
14

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

我的回答表明,根据几个备受推崇的消息来源(Herb Sutter 和 Matt Austern),当前的 C++ 标准确实需要在某些条件下(一旦你称之为假设是 a )std::string将其数据连续存储,并且这一事实几乎迫使任何实施。str[0]strstd::string

基本上,如果您结合所做出的承诺string::data()string::operator[]()得出结论,则&str[0]需要返回一个连续的缓冲区。因此 Austern 建议委员会明确说明这一点,显然这就是 0x 标准中会发生的事情(或者他们现在是否称其为 1x 标准?)。

所以严格来说,一个实现不必std::string使用连续存储来实现,但它几乎必须按需执行。您的示例代码通过传入&buffer[0].

链接:

于 2010-02-13T04:54:36.390 回答
0

编辑:您想调用&buffer[0]而不是 buffer.data(),因为[]返回非const引用并通知对象其内容可能会意外更改。


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

非常有可能某些实现将为所有未初始化的字符串创建一个缓冲区,除了长度设置为 10 或其他。

使用带有/vector的数组甚至数组。如果您确实无法复制缓冲区,请在更改之前合法地将字符串初始化为唯一的东西。new[]delete[]

于 2010-02-13T07:37:06.450 回答
-1

结果是未定义的,我不会这样做。在现代 c++ 堆中,读取向量然后转换为字符串的成本是微不足道的。VS 你的代码在 Windows 9 中死掉的风险

另外,在 &buffer[0] 上不需要 const_cast 吗?

于 2010-02-13T02:01:06.077 回答
-2

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

于 2010-02-13T02:07:44.273 回答