C++ 当访问要推入联合向量的字符串的字符时,向量中的字符串会被弄乱
下面是一个(显示问题的简单示例): 我只是访问字符串中的第一个字符;我什么都没做!但是,如果我注释掉该行,我会得到正确的输出:C++ 当访问要推入联合向量的字符串的字符时,向量中的字符串会被弄乱,c++,string,vector,unions,C++,String,Vector,Unions,下面是一个(显示问题的简单示例): 我只是访问字符串中的第一个字符;我什么都没做!但是,如果我注释掉该行,我会得到正确的输出: test ------- test another test ------- (etc....) ------- test another test even more test test test test test test lotsa test 但是有了这句话,我。。。呃,我不知道发生了什么事。这是输出: test ------- ä7R another tes
test
-------
test
another test
-------
(etc....)
-------
test
another test
even more test
test test
test test test
lotsa test
但是有了这句话,我。。。呃,我不知道发生了什么事。这是输出:
test
-------
ä7R
another test
-------
ä7R
even more test
even more test
-------
test test
ä7R
ä7R
test test
-------
test test
test test test
test test test
test test
test test test
-------
lotsa test
ä7R
ä7R
lotsa test
ä7R
lotsa test
-------
lotsa test
ä7R
ä7R
lotsa test
ä7R
lotsa test
代码似乎没有什么问题,但很明显我做错了什么。为什么向量会像这样被破坏,它到底是如何由于不处理字符串的第一个字符而导致的?由
string::c_str()
返回的const char*
的生存期是有限的。如果您试图保留这些字符串,则需要将它们复制到专用存储中
每次迭代时,字符串s
都会被tokens
中的新字符串替换。当for
循环在下一次迭代中将一个新字符串分配给s
时,允许将上一次迭代的c_str()
无效
它能够工作的事实可能是实现的幸运运气:在引擎盖下,s
可能从tokens
中的条目借用了字符串的存储空间。然而,对操作符[]
的调用可能导致它自己制作字符串的私有副本。这可以解释c_str()
的行为差异
要将副本保存在专用存储中,需要为其分配空间并将字符串复制到其中。下面这样的代码就足够了:
nObj.oString = new char[s.size() + 1]; // allocate the space
std::strcpy( nObj.oString, s.c_str() ); // copy in the string
现在,从技术上讲,如果它包含ASCII NUL,则不会复制整个字符串。您的原始代码并不关心这些,我上面的建议不会改变这一点。:-)您可以在
中找到std::strcpy()
请注意,因为您已经为自己的存储分配了new[]
,所以在以后处理完它时,您必须记住delete[]
,否则会出现内存泄漏。并确保您使用的是delete[]
,而不是delete
或free()
主要问题来自您的exec
:
for (string s : tokens)
{
ObjectNative nObj;
nObj.oString = s.c_str();
语义上,您的标记
向量是一个副本。此外,for(string s:tokens)
s
也是循环中的临时副本。当循环退出时,s
将不再存在。所以当你做一些类似的事情时:
nObj.oString = s.c_str();
砰!您现在有一个悬空的const char*
。现在您的程序有未定义的行为,因为之后您尝试在main
中打印该堆栈。s[0]代码>导致任何行为差异在这一点上都是不相关的
根据您的尝试,我将采取以下措施来解决此问题:
- 将原型更改为
void exec(常量向量和令牌、向量和堆栈)代码>
- 将
s
修改为引用。例如,for(const string&s:tokens)
。只要标记
不超过堆栈
,这应该是正常的
好的,那我该怎么做呢?对不起,我是C++新手。为什么访问第一个字符会影响输出?@Doorknob:实际上,我不能100%确定为什么它会使c_str()
无效。据介绍,c_str()
只有通过将字符串的非常量引用传递给库函数,或调用字符串上的非常量成员(不包括[]
和其他一些成员)才能使c_str()
无效。@doorknold:就分配存储和复制它而言,您可以执行char*tmp=new char[s.size()+1];std::strcpy(tmp,s.c_str())
,并将tmp
分配给nObj.oString
。记住以后处理完字符串后要删除[]
。@Doorknob:哦,等等,我知道字符串为什么会变得无效。它们应该只对一次迭代有效,因为for
循环正在按顺序将标记中的每个字符串分配给s
。事实上,它曾经奏效是一个幸运的巧合。它可能是借用了tokens
中字符串中的存储空间,而没有s[0]
,但是一旦你打电话给operator[]
,它就不得不停止借用存储空间,并制作自己的本地副本。好的,谢谢,我会试试看。如果你把它编辑成你的答案,并且它有效,我会接受它。谢谢对标记中的字符串进行任何修改都会导致问题。如果这是一个解析器,那么这个向量可能会被回收…@joe True。在我看来,op应该避免使用原始constchar*
。表示对象的类型
需要更好地封装。同意。如果是我,我只会有一个<代码> STD::String ,我可能会在 Ung/<代码>上考虑多态性。
for (string s : tokens)
{
ObjectNative nObj;
nObj.oString = s.c_str();
nObj.oString = s.c_str();