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

C++ 使用std::basic_string<;是否合理;t>;作为目标C+时的连续缓冲区+;03?,c++,string,winapi,stl,c++03,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

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

结果未定义,我不会这样做。在现代C++堆中,读入向量然后转换成字符串的代价微乎其微。VS您的代码在windows 9中死亡的风险


另外,这是否需要一个常量强制转换&buffer[0]?

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

< P>我认为假定STD::String连续地分配它的存储是相当安全的。 目前,
std::string
的所有已知实现都连续分配空间

此外,C++0x()(编辑:警告,直接链接到大PDF)的当前草稿要求空间被连续地分配(<21.4.1/5):

类字符对象 应存储基本字符串对象 连续地。也就是说,对任何人来说 基本字符串对象,标识 &*(s.begin()+n)==&s.begin()+n 应适用于n的所有值
前一段时间,有一个问题是,是否能够将
std::string
作为一个字符数组写入存储器,这取决于
std::string
的内容是否连续:

< P> >我的回答表明,根据一对夫妇的良好来源(萨特和Matt Austern),当前的C++标准要求<代码> STD::String < /C>在一定条件下存储它的数据(一旦调用了代码> STR [0 ] < /Cord>假定“代码> STR 是<代码> STD::String )这一事实在很大程度上迫使任何实施

基本上,如果您将
string::data()
string::operator[]()
所做的承诺结合起来,您就会得出结论,
&str[0]
需要返回一个连续的缓冲区。因此奥斯特恩建议委员会明确这一点,很显然,0x标准(或者他们现在称之为1x标准)中会出现这种情况

因此严格来说,实现不必使用连续存储来实现
std::string
,但它必须根据需要来实现。您的示例代码就是通过传入
&buffer[0]
实现的

链接:


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


执行
buffer.data()
会更干净,但您应该更关心结构之间共享的内存,而不是连续内存<代码>字符串实现可以而且确实期望在修改对象时被告知<代码>字符串::数据特别要求程序不修改返回的内部缓冲区

除了将长度设置为10或其他值之外,一些实现很可能会为所有未初始化的字符串创建一个缓冲区


使用
向量
甚至是带有
新[]
/
删除[]
的数组。如果确实无法复制缓冲区,请在更改之前合法地将字符串初始化为唯一的字符串。

字符串实现与windows API无关,因此与用户使用的windows版本无关。是的,根据标准,这是未定义的行为。但对我所知道的每一个编译器来说都是可以的。我很好奇到底有多少编译器利用了标准赋予它们的自由度。实际上,新版本的windows附带了新版本的c运行时。关键是,未定义意味着它在未来可能会神秘地改变,为什么要冒险呢?实际上,我从来没有发现过一个字符串impl不能将字符串作为一个好的经典数组进行布局。但我还是不想这么做,这并不意味着它在未来会神秘地改变。未定义意味着编译器可以按照自己的意愿实现它。一旦代码被编译,它的行为就不能改变,除非它调用动态库。由于字符串不调用DLL,windows的未来版本将不会破坏它。(除非我使用动态C运行时——那么我认为这是可能的,但仍然不太可能)我不是在问这样做是否是个好主意——我是在问是否有编译器关心这个问题。
另外,这不需要常量强制转换&buffer[0]?
我们玩得开心吗?:-)我所见过的所有编译器都按照我们都期望的方式进行编译。好啊但我仍然不会这么做,除非你确定MSVC成功地给了你RVO(即使你有两个不同的回报,一个是临时的,一个是变量名),那么你就不“允许”担心额外的副本;-)我不相信RVO会优化向量之间的拷贝