我正在使用旧的C风格界面进行战斗。我有一个带有这样签名的函数:
/// if return_value == NULL only the length is returned
void f( char * return_value, size_t * size_only_known_at_runtime);
我的问题是,以下代码是否安全?
std::size required;
f( NULL, &required );
std::string s;
s.resize(required);
f( &s[0], &required );
有没有更好的方法将数据输入字符串?
答案 0 :(得分:7)
是的,它是安全的,至少从C ++ 11中是明确的。来自[string.require],强调我的:
basic_string
对象中的类似char的对象应连续存储。也就是说,对于任何basic_string 对象s,&*(s.begin() + n) == &*s.begin() + n
的所有值都应保留n
0 <= n < s.size()
。
这是DR 530的决议。在C ++ 11之前,这在标准中并不明确,尽管无论如何它都是在实践中完成的。
在C ++ 14中,此要求已移至[basic.string]:
basic_string
是一个连续的容器(23.2.1)。
其中[container.requirements.general]:
连续容器是一个支持随机访问迭代器(24.2.7)及其成员的容器 类型
iterator
和const_iterator
是连续的迭代器(24.2.1)。
其中[iterator.requirements.general]:
进一步满足对于整数值
n
和可解除引用的迭代器值的要求的迭代器a
和(a + n)
,*(a + n)
相当于*(addressof(*a) + n)
,称为连续迭代器。
答案 1 :(得分:1)
问题是代码是否
std::size_t required_size;
f( nullptr, &required_size );
std::string s;
s.resize( required_size );
f( &s[0], &required_size );
是安全的。
这取决于假设哪个C ++标准,但由于在C ++ 03和C ++ 98中required_size
= 0的情况下它是未定义的行为,所以一般答案是否,一般来说都不安全。
在C ++ 03 std::string
没有正式保证有一个连续的缓冲区,但实际上所有现存的实现都有连续的缓冲区。无论如何,现在在C ++ 11之后,连续缓冲区保证正式合并到标准中,将不会出现任何具有非连续缓冲区的新C ++ 03实现。因此,这不是问题。
问题在于C ++ 03 std::basic_string::operator[]
定义如下:
“ 返回:如果
pos < size()
,则返回data()[pos]
。否则,如果pos == size()
,const
版本将返回charT()
。否则,行为未定义。
因此,对于大小为0的非const
字符串s
,在C ++ 03中使用Undefined Behavior™来进行索引s[0]
。
在C ++ 11中,相应的段落§21.4.3/ 2表示结果是*(begin() + pos)
if pos < size()
,否则引用类型为T
的对象价值charT()
;参考值不得修改。“
无论编译器实现哪种C ++标准,这里的代码都有效:
std::size_t required_size;
f( NULL, &required_size ); // Establish required buffer size.
if( required_size > 0 )
{
std::string s( required_size, '#' );
f( &s[0], &required_size );
s.resize( strlen( &s[0] ) );
}