我的同事的代码是这样的:C++中的字符串[length()],可以吗?
void copy(std::string const& s, char *d) {
for(int i = 0; i <= s.size(); i++, d++)
*d = s[i];
}
他的应用程序崩溃,我认为这是因为这个访问s
超出范围,因为条件应该只到s.size() - 1
。
但是旁边的其他人说过去有关于这是合法的讨论。任何人都可以请为我清除这个?
我的同事的代码是这样的:C++中的字符串[length()],可以吗?
void copy(std::string const& s, char *d) {
for(int i = 0; i <= s.size(); i++, d++)
*d = s[i];
}
他的应用程序崩溃,我认为这是因为这个访问s
超出范围,因为条件应该只到s.size() - 1
。
但是旁边的其他人说过去有关于这是合法的讨论。任何人都可以请为我清除这个?
让我们抛开可能性,即*d
是无效的,因为这无关什么这个问题似乎是冲着:无论是否在指数std::string::size()
访问“元素”的时候std::string operator[]()
有明确定义的行为。
的C++ 03标准品具有string::operator[]()
下面的描述中(21.3.4 “basic_string
元素访问”):
const_reference operator[](size_type pos) const; reference operator[](size_type pos);
返回:如果
pos < size()
,返回data()[pos]
。否则,如果pos == size()
,const版本返回charT()
。否则,行为是不确定的。
由于在示例代码s
是const
,行为被很好地定义和s[s.size()]
将返回一个空字符。但是,如果s
不是const string
,则行为将是未定义的。
C++ 11弥补了const
版本的这种奇怪行为在此边缘情况下的行为与非const版本行为的差异。 C++ 11 21.4.5 “basic_string
元素访问” 说:
const_reference operator[](size_type pos) const; reference operator[](size_type pos);
要求:
pos <= size()
。返回:
*(begin() + pos
)如果pos < size()
,否则参考 到类型T的对象与值charT()
;参考值 不得修改。
因此,对于C++ 11编译器,无论string
是否为const
,行为都是明确定义的。
与这个问题无关,我觉得有点奇怪,C++ 11说“引用的值不应该被修改” - 我不清楚这个子句是否仅适用于pos == size()
的情况。我很确定有很多现有的代码可以执行诸如s[i] = some_character;
的工作,其中s
是非常量的std:string
和i < s.size()
。现在是不确定的行为?我怀疑该条款仅适用于特殊情况charT()
对象。
另一个有趣的事情是,两种标准似乎都不要求为s[s.size()]
返回的对象的地址与以s[s.size() - 1]
返回的对象的地址有任何关系。换句话说,看起来返回的charT()
引用不必与字符串数据的末尾连续。我怀疑这是为了给实现者一个选择,如果需要的话,只返回一个引用到该哨兵元素的单个静态副本(这也可以解释C++ 11的“不得修改”限制,假设它仅适用于特殊案件)。
我发现'at'有趣,但是,不允许以'size()'作为索引来调用。 –
感谢您的深度分析。 –
reference operator[](size_type pos); const_reference operator[](size_type pos) const;
如果
pos==size()
,
- const版本返回到与值表()(空字符)的字符的参考。 (直到C++ 11)
- 两个版本都返回对值为CharT()(空字符)的字符的引用。通过非const引用修改空字符会导致未定义的行为。 (因为C++ 11)
所以这是OK,只要你不修改的空字符。
OP的代码不会尝试修改std :: string,它会尝试从字符串读取并将其放入char数组中。 –
需要说明的是,如果使用C++ 11之前的编译器,如果s不是const,那么对[s.size()]的访问是不确定的 - 只能在问题代码中访问因为's'是'const'(对于C++ 11之前的编译器)。它与null字符是否被修改无关,只是's'是否是'const'。当然,这些都没有提到任何关于'* d'可能无效的可能性。 –
我觉得引用一个网站来证明标准符合性很有意思,让我挖一下;) –
如果你想那样做(你collegue的代码试图复制终止\0
为好),你可以
c_str()
。i < s.size()
一起使用循环,然后手动追加\0
。编辑:
好,由其他的答案来看,我更倾向于现在认为Abyx的评论是正确的:数组d
可溢出(或者甚至有可能不会被分配)。先检查一下。
但是请确保您也复制\0
!
我会更关心目标指针。为什么这个函数没有大小参数? – LaC
也许你应该尝试复制's.c_str()',如果你想在复制空终止符... – Yaniro
也许'd'有错误的容量 – Abyx