我通过将它的内存分配给堆来创建了一个向量。然后我创建10个字符串对象也分配给堆内存并将它们存储在向量中。我试图使用delete
运算符释放与每个新字符串对象关联的内存,但我不是如何做到的。我正在使用C ++ 11。
#include <vector>
#include <string>
#include <iostream>
using namespace std;
int main()
{
vector<string> *v = new vector<string>;
for(int i = 0; i < 10; i++) {
// allocate a new string object on the heap
string *a = new string("Hello World");
//de-reference the string object
v->push_back(*a);
}
// show the contents of the vector
for(auto i = v->begin(); i != v->end(); ++i) {
// okay so this makes a lot more sense than:
// const string &s = *i;
// this way we create a pointer to a string object
// it is a lot more clear this way
const string *s = &(*i);
cout << *s << " " << s->length() << endl;
}
cout << endl << endl;
for(vector<string>::iterator it = v->begin(); it != v->end(); ++it) {
delete ⁢
v->erase(it);
}
for(auto i = v->begin(); i != v->end(); ++i) {
cout << *i << endl;
}
cout << endl << "Size: " << v->size() << endl;
delete v;
}
g++ -std=c++11 main.cc -o main
我的错误是并非所有对象都被删除。我最后在最后4个语句后留下了5个对象。一旦完成这些操作,我期望向量内部有零个对象。
我的输出:
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World 11
Hello World
Hello World
Hello World
Hello World
Hello World
Size: 5
问题是并非所有对象都被删除。
答案 0 :(得分:5)
我认为你在无数问题中担心的特殊问题是你的for循环并没有删除所有项目,即:
for(vector<string>::iterator it = v->begin(); it != v->end(); ++it) {
delete ⁢
v->erase(it);
}
您的问题是您正在更改正在迭代的向量,这会导致未定义的行为,因为您没有删除所有值。 (只要不添加或删除值,向量的迭代器才有效。)
我可以解释为什么它只做5,但答案不是跨平台的。在这种情况下,编译器可以随意做任何事情。对于编译器来说,让恶魔飞出你的鼻子也同样有效。
基本上,你正在删除一个值,然后他们转移到下一个索引。所以你在0处删除了什么,它会将1处的值拉到0处。然后你移动到索引1,它包含以前在索引2中的内容。然后你删除它。基本上,您从向量中删除所有偶数索引。
编辑:将问题减少到可重复的最小值:
std::vector<int> vals;
for (int i = 0; i < 11; i++0) vals.push_back(i);
for (std::vector<int>::iterator i = vals.begin(); i != vals.end(); ++i)
{
vals.erase(i);//after this point, i's behavior is undefined!
}
编辑3:列举所有代码问题(基于元对话的建议操作)
new std::string
将简单地将指针分配给字符数组和堆中的大小。所以这也值得注意。std::vector<T*>
。 std::vector<T>
将是T
。std::string& s = *it
比获取地址更具可读性。&it
的类型为std::vector<string>::iterator*
。为什么这可能不会崩溃和烧毁的是迭代器类型只包含内置类型,并且在此之后你没有做太多(你可能已经为自己设置了一些美味的堆栈损坏)。如果你有一个std::vector<T*>
(匹配项目1),并且该向量具有唯一所有权,那么你需要这样做来清理它: delete &(*it);
但是做std::vector<std::unique_ptr<T>>
这样的事情会好得多,而且从不担心。
答案 1 :(得分:2)
问题是并非所有对象都被删除。
这是因为当你填充向量时你正在泄漏字符串。
for(int i = 0; i < 10; i++) {
string *a = new string("Hello World"); // Leak: who deletes a? Nobody!
v->push_back(*a);
}
这是一种避免特定泄漏的方法:
for(int i = 0; i < 10; i++) {
v->push_back("Hello World");
}
但是,您正在动态分配v
,并且没有理由这样做。在C ++中,这将是一种更简单和惯用的方法。与您的版本不同,它不涉及内存泄漏或未定义的行为:
int main()
{
vector<string> v(10, "Hello World");
for (auto& s : v)
cout << s.length() << endl;
}
你不需要指针。您无需致电new
。您无需担心内存管理问题。
答案 2 :(得分:1)
当您使用v-&gt; push_back(* a)时,您正在向量上推送字符串的副本;命令。如果你不想这样做,你需要让你的向量成为字符串指针的向量,然后将指针自身推到向量上。
答案 3 :(得分:0)
我不明白你为什么要动态分配字符串,即使你是按值存储它。这个片段即使是教育目的也没有意义,除非你学习如何在C ++中泄漏内存。
for(int i = 0; i < 10; i++) {
// allocate a new string object on the heap
string *a = new string("Hello World");
//de-reference the string object
v->push_back(*a);
}
如果你想在任何stl容器中存储指针,那么我建议使用一些智能指针(EXCLUDING AUTO_PTR),如boost :: shared_ptr。他们会为您处理内存管理。