这是一个SSCCE (简单的例子来说明问题):
#include <iostream>
#include <string>
#include <vector>
using namespace std;
enum Type {oInt, oFloat, oString, oArray};
struct Object; // fwd decl for union
union ObjectNative {
int oInt;
float oFloat;
const char* oString;
vector<Object>* oArray;
};
struct Object {
Type type;
ObjectNative obj;
};
vector<Object> exec(vector<string> tokens, vector<Object> stack);
void printStack(vector<Object> stack);
int main() {
vector<string> tokens{"test", "another test", "even more test", "test test", "test test test", "lotsa test"};
vector<Object> stack;
stack = exec(tokens, stack);
printStack(stack);
return 0;
}
vector<Object> exec(vector<string> tokens, vector<Object> stack) {
for (string s : tokens) {
ObjectNative nObj;
// !!!!!!!!!!!!!!!!!!!!!! THIS LINE !!!!!!!!!!!!!!!!!!!!!!
s[0];
nObj.oString = s.c_str();
Object obj = Object{oString, nObj};
stack.push_back(obj);
// debugging lines
printStack(stack);
cout << "-------" << endl;
}
return stack;
}
void printStack(vector<Object> stack) {
for (unsigned int i = 0; i < stack.size(); i ++) {
Object o = stack[i];
cout << o.obj.oString;
cout << endl;
}
}
注意我在 exec
函数中标记的行:
s[0];
我只是访问字符串中的第一个字符;我什至没有用它做任何事!但是,如果我注释掉该行,我会得到正确的输出:
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
看起来代码没有任何问题,但显然我做的事情非常错误。为什么 vector 会被这样损坏,它到底是如何因对字符串的第一个字符不执行任何操作而导致的?
最佳答案
const char *
的生命周期返回者 string::c_str()
是有限的。如果您想保留这些字符串,则需要将它们复制到专用存储中。
字符串s
被 tokens
中的新字符串替换在每次迭代中。当 for
循环将一个新字符串分配给 s
在下一次迭代中,允许使 c_str()
无效。来自上一次迭代的结果。
事实上,它能起作用可能是实现的幸运侥幸:在幕后,s
可能从 tokens
中的条目借用了字符串的存储空间。 。调用operator[]
然而,可能导致它制作自己的字符串的私有(private)拷贝。这可以解释 c_str()
的行为差异。 .
要将拷贝保存在专用存储中,您需要为其分配空间并将字符串复制到其中。像下面这样的代码就足够了:
nObj.oString = new char[s.size() + 1]; // allocate the space
std::strcpy( nObj.oString, s.c_str() ); // copy in the string
现在,从技术上讲,这不会复制整个 string
如果它包含 ASCII NUL。您的原始代码并不关心这些,我上面的建议也不会改变这一点。 :-) 你可以找到std::strcpy()
在<cstring>
.
请注意,因为您已使用 new[]
分配了自己的存储空间,你必须记住delete[]
等你用完之后再做,否则会出现内存泄漏。并确保您使用 delete[]
,不是delete
或free()
.
关于c++ - 当访问要插入 union vector 中的字符串字符时, vector 中的字符串会变得困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20534016/