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

时间:2010-02-13 01:36:11

标签: c++ string winapi stl c++03

我知道在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是连续的,因此在定位该标准时,上述问题不是问题。

5 个答案:

答案 0 :(得分:24)

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

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

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

  

一个类似char的对象   应存储basic_string对象   连续。也就是说,对任何人来说   basic_string对象s,标识   &amp; *(s.begin()+ n)==&amp; * s.begin()+ n   应保留所有n值   那个0&lt; = n&lt; s.size()。

因此,当前或将来使用非连续存储实现std::string的可能性基本上为零。

答案 1 :(得分:13)

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

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

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

严格地说,实现不必使用连续存储来实现std::string,但它必须非常需要。您的示例代码通过传递&buffer[0]来实现这一点。

链接:

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

修改:您要拨打&buffer[0] buffer.data(),因为[]会返回非const } reference和 通知对象其内容可能会意外更改。


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

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

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

答案 4 :(得分:-2)

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