I'm fighting with an old c-style-interface. I have a function with a signature like this:
我正在与旧的C风格界面作斗争。我有一个像这样的签名功能:
/// if return_value == NULL only the length is returned
void f( char * return_value, size_t * size_only_known_at_runtime);
My question is, is the following code safe?
我的问题是,以下代码是否安全?
std::size required;
f( NULL, &required );
std::string s;
s.resize(required);
f( &s[0], &required );
Is there a better way to get the data into the string?
有没有更好的方法将数据输入字符串?
2 个解决方案
#1
Yes, it's safe, at least explicitly from C++11. From [string.require], emphasis mine:
是的,它是安全的,至少从C ++ 11中是明确的。来自[string.require],强调我的:
The char-like objects in a
basic_string
object shall be stored contiguously. That is, for any basic_string object s, the identity&*(s.begin() + n) == &*s.begin() + n
shall hold for all values ofn
such that0 <= n < s.size()
.basic_string对象中的char类对象应连续存储。也就是说,对于任何basic_string对象,标识&*(s.begin()+ n)==&* s.begin()+ n应该适用于n的所有值,使得0 <= n
This was the resolution of DR 530. Before C++11, this was not explicit in the standard, although it was done in practice anyway.
这是DR 530的解决方案。在C ++ 11之前,这在标准中并不明确,尽管无论如何都是在实践中完成的。
In C++14, this requirement got moved to [basic.string]:
在C ++ 14中,此要求已移至[basic.string]:
A
basic_string
is a contiguous container (23.2.1).basic_string是一个连续的容器(23.2.1)。
where [container.requirements.general]:
A contiguous container is a container that supports random access iterators (24.2.7) and whose member types
iterator
andconst_iterator
are contiguous iterators (24.2.1).连续容器是一个支持随机访问迭代器(24.2.7)的容器,其成员类型iterator和const_iterator是连续迭代器(24.2.1)。
where [iterator.requirements.general]:
Iterators that further satisfy the requirement that, for integral values
n
and dereferenceable iterator valuesa
and(a + n)
,*(a + n)
is equivalent to*(addressof(*a) + n)
, are called contiguous iterators.迭代器进一步满足以下要求:对于整数值n和可解除引用的迭代器值a和(a + n),*(a + n)等价于*(addressof(* a)+ n),称为连续迭代器。
#2
The question is whether the code
问题是代码是否存在
std::size_t required_size;
f( nullptr, &required_size );
std::string s;
s.resize( required_size );
f( &s[0], &required_size );
is safe.
That depends on which C++ standard one assumes, but since it's Undefined Behavior for the case of required_size
= 0 in C++03 and C++98, the general answer is no, it's not safe in general.
这取决于假设哪个C ++标准,但由于在C ++ 03和C ++ 98中对于required_size = 0的情况它是未定义的行为,一般的答案是否定的,一般来说它不安全。
In C++03 std::string
was not formally guaranteed to have a contiguous buffer, but in practice all extant implementation did have contiguous buffer. Anyway, now after C++11, where the contiguous buffer guarantee was formally incorporated in the standard, there will not appear any new C++03 implementations with non-contiguous buffer. Hence that isn't a problem.
在C ++ 03中,std :: string没有正式保证有一个连续的缓冲区,但实际上所有现存的实现都有连续的缓冲区。无论如何,现在在C ++ 11之后,连续缓冲区保证正式合并到标准中,将不会出现任何具有非连续缓冲区的新C ++ 03实现。因此,这不是问题。
The problem is rather that in C++03 std::basic_string::operator[]
was defined as follows:
问题在于,在C ++ 03中,std :: basic_string :: operator []的定义如下:
C++03 §21.3.4/1:” Returns: If
pos < size()
, returnsdata()[pos]
. Otherwise, ifpos == size()
, theconst
version returnscharT()
. Otherwise, the behavior is undefined.“返回:如果pos
(),则返回data()[pos]。否则,如果pos>
So, for a non-const
string s
of size 0, in C++03 it was Undefined Behavior™ to do the indexing s[0]
.
因此,对于大小为0的非常量字符串s,在C ++ 03中,使用Undefined Behavior™来进行索引s [0]。
In C++11 the corresponding paragraph §21.4.3/2 says instead that the result is “*(begin() + pos)
if pos < size()
, otherwise a reference to an object of type T
with value charT()
; the referenced value shall not be modified.”
在C ++ 11中,相应的段落§21.4.3/ 2表示如果pos
Here's code that works regardless of which C++ standard the compiler implements:
无论编译器实现哪种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] ) );
}
#1
Yes, it's safe, at least explicitly from C++11. From [string.require], emphasis mine:
是的,它是安全的,至少从C ++ 11中是明确的。来自[string.require],强调我的:
The char-like objects in a
basic_string
object shall be stored contiguously. That is, for any basic_string object s, the identity&*(s.begin() + n) == &*s.begin() + n
shall hold for all values ofn
such that0 <= n < s.size()
.basic_string对象中的char类对象应连续存储。也就是说,对于任何basic_string对象,标识&*(s.begin()+ n)==&* s.begin()+ n应该适用于n的所有值,使得0 <= n
This was the resolution of DR 530. Before C++11, this was not explicit in the standard, although it was done in practice anyway.
这是DR 530的解决方案。在C ++ 11之前,这在标准中并不明确,尽管无论如何都是在实践中完成的。
In C++14, this requirement got moved to [basic.string]:
在C ++ 14中,此要求已移至[basic.string]:
A
basic_string
is a contiguous container (23.2.1).basic_string是一个连续的容器(23.2.1)。
where [container.requirements.general]:
A contiguous container is a container that supports random access iterators (24.2.7) and whose member types
iterator
andconst_iterator
are contiguous iterators (24.2.1).连续容器是一个支持随机访问迭代器(24.2.7)的容器,其成员类型iterator和const_iterator是连续迭代器(24.2.1)。
where [iterator.requirements.general]:
Iterators that further satisfy the requirement that, for integral values
n
and dereferenceable iterator valuesa
and(a + n)
,*(a + n)
is equivalent to*(addressof(*a) + n)
, are called contiguous iterators.迭代器进一步满足以下要求:对于整数值n和可解除引用的迭代器值a和(a + n),*(a + n)等价于*(addressof(* a)+ n),称为连续迭代器。
#2
The question is whether the code
问题是代码是否存在
std::size_t required_size;
f( nullptr, &required_size );
std::string s;
s.resize( required_size );
f( &s[0], &required_size );
is safe.
That depends on which C++ standard one assumes, but since it's Undefined Behavior for the case of required_size
= 0 in C++03 and C++98, the general answer is no, it's not safe in general.
这取决于假设哪个C ++标准,但由于在C ++ 03和C ++ 98中对于required_size = 0的情况它是未定义的行为,一般的答案是否定的,一般来说它不安全。
In C++03 std::string
was not formally guaranteed to have a contiguous buffer, but in practice all extant implementation did have contiguous buffer. Anyway, now after C++11, where the contiguous buffer guarantee was formally incorporated in the standard, there will not appear any new C++03 implementations with non-contiguous buffer. Hence that isn't a problem.
在C ++ 03中,std :: string没有正式保证有一个连续的缓冲区,但实际上所有现存的实现都有连续的缓冲区。无论如何,现在在C ++ 11之后,连续缓冲区保证正式合并到标准中,将不会出现任何具有非连续缓冲区的新C ++ 03实现。因此,这不是问题。
The problem is rather that in C++03 std::basic_string::operator[]
was defined as follows:
问题在于,在C ++ 03中,std :: basic_string :: operator []的定义如下:
C++03 §21.3.4/1:” Returns: If
pos < size()
, returnsdata()[pos]
. Otherwise, ifpos == size()
, theconst
version returnscharT()
. Otherwise, the behavior is undefined.“返回:如果pos
(),则返回data()[pos]。否则,如果pos>
So, for a non-const
string s
of size 0, in C++03 it was Undefined Behavior™ to do the indexing s[0]
.
因此,对于大小为0的非常量字符串s,在C ++ 03中,使用Undefined Behavior™来进行索引s [0]。
In C++11 the corresponding paragraph §21.4.3/2 says instead that the result is “*(begin() + pos)
if pos < size()
, otherwise a reference to an object of type T
with value charT()
; the referenced value shall not be modified.”
在C ++ 11中,相应的段落§21.4.3/ 2表示如果pos
Here's code that works regardless of which C++ standard the compiler implements:
无论编译器实现哪种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] ) );
}