C++ 内存管理和向量
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/965401/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
C++ memory management and vectors
提问by Columbo
I'm getting very confused with memory management in relation to vectors and could do with some basic concepts explaining.
我对与向量相关的内存管理感到非常困惑,并且可以解释一些基本概念。
I have a program that uses big vectors. I created the vectors with the newoperator and release them at the end of the program with deleteto get the memory back.
我有一个使用大向量的程序。我使用new运算符创建了向量,并在程序结束时使用delete释放它们以取回内存。
My question is, if the program crashes or gets aborted for what ever reason, the deletelines will be missed, is there a way to recover the memory even in this scenario.
我的问题是,如果程序因任何原因崩溃或中止,删除行将丢失,即使在这种情况下,是否有办法恢复内存。
I also have some other large vectors that I assign without the newkeyword. I have read that these will be created on the heap but do not need to be deallocated in anyway as the memory management is dealt with 'under the hood'. However I am not sure this is the case as every time I run my program I lose RAM.
我还有一些其他的大向量,我在没有new关键字的情况下分配了这些向量。我已经读到这些将在堆上创建,但不需要以任何方式解除分配,因为内存管理是在“幕后”处理的。但是,我不确定是否是这种情况,因为每次运行我的程序时都会丢失 RAM。
So my second question is, can vectors created without the newkeyword really be left to their own devices and trusted to clear up after themselves even if code is aborted mid flow.
所以我的第二个问题是,即使代码在流程中中止,在没有new关键字的情况下创建的向量是否真的可以留给他们自己的设备并信任他们自己清理。
And I suppose a third question that has just sprung to mind is, if Vectors are automatically created on the heap why would you ever use the newkeyword with them? Thanks for reading, ben
我想我刚刚想到的第三个问题是,如果 Vectors 是在堆上自动创建的,你为什么要对它们使用new关键字?感谢阅读,本
回答by Tobias
I suspect your questions are about std::vector< T > (as opposed to an array T[]).
我怀疑您的问题是关于 std::vector< T > (而不是数组 T[])。
- When your application crashes or gets aborted for whatever reason, the OS reclaims the memory. If not you are using a truly rare OS and have discovered a bug.
- You need to distinguish between the memory used by the vector itself and the memory of its contained objects. The vector can be created on the heap or on the stack as you noted, the memory it allocates for its contained elements is always on the heap (unless you provide your own allocator which does something else). The memory allocated by the vector is managed by the implementation of vector, and if the vector is destructed (either because it goes out of scope for a vector on the stack or because you delete a vector on the heap) its destructor makes sure that all memory is freed.
- 当您的应用程序因任何原因崩溃或中止时,操作系统会回收内存。如果不是,您正在使用真正罕见的操作系统并发现了一个错误。
- 您需要区分向量本身使用的内存与其包含的对象的内存。正如您所指出的,向量可以在堆上或堆栈上创建,它为其包含的元素分配的内存始终在堆上(除非您提供自己的分配器来执行其他操作)。vector 分配的内存由 vector 的实现管理,如果 vector 被析构(因为它超出了栈上 vector 的作用域,或者因为你删除了堆上的一个 vector),它的析构函数会确保所有内存被释放。
回答by rlbond
Don't use new
to create vectors. Just put them on the stack.
不要new
用于创建向量。只需将它们放在堆栈中。
The vector's destructor automatically invokes the destructor of each element in the vector. So you don't have to worry about deleting the objects yourself. However, if you have a vector of pointers, the objects that the pointers refer to will notbe cleaned up. Here's some example code. For clarity I am leaving out most details:
向量的析构函数会自动调用向量中每个元素的析构函数。所以你不必担心自己删除对象。但是,如果您有一个指针向量,则不会清除指针所指的对象。这是一些示例代码。为了清楚起见,我省略了大部分细节:
class HeapInt
{
public:
HeapInt(int i) {ptr = new int(i);}
~HeapInt() {delete ptr;}
int& get() {return *ptr;}
private:
int* ptr;
};
int main()
{
// this code DOES NOT leak memory
std::vector<HeapInt> vec;
for (int i = 0; i < 10; ++i)
{
HeapInt h(i);
vec.push_back(h);
}
return 0;
}
Even if main() throws an exception, no memory is lost. However, this code doesleak memory:
即使 main() 抛出异常,也不会丢失内存。但是,此代码确实会泄漏内存:
int main()
{
// this code though, DOES leak memory
std::vector<int*> vec;
for (int i = 0; i < 10; ++i)
{
int* ptr = new int(i);
vec.push_back(ptr);
}
// memory leak: we manually invoked new but did not manually invoke delete
return 0;
}
回答by Doug T.
Yes you can trust vectors to clean up after themselves.
是的,您可以相信载体会自行清理。
HOWEVERYou cannot trust the stuff vector holds to cleanup after itself. What needs to be cleaned up could be something that persists outside of your application. If its memory, this isn't a worry. If its making sure the XML tags are all closed, then the OS isn't going to be able to help you.
但是,您不能相信东西向量会在其自身之后进行清理。需要清理的内容可能会在您的应用程序之外持续存在。如果它的内存,这不是一个担心。如果它确保 XML 标签全部关闭,那么操作系统将无法帮助您。
For example, what if you have a vector of some wonky lock object like this:
例如,如果你有一个像这样一些不稳定的锁对象的向量怎么办:
class CLock
{
public:
CLock() {}
~CLock() {}
void Lock(...) {...}
void Unlock(...) {...}
};
std::vector<CLock> myLockVec;
How would your vector of CLock's know to unlock everything when its done? Vector's aren't built to know about locks.
您的时钟向量如何知道在完成后解锁所有内容?Vector 不是为了了解锁而构建的。
This is essentially the same situation as having a vector of pointers:
这与具有指针向量的情况基本相同:
std::vector<int*> myIntVec;
How does the vector know which pointers here have been deleted and NULL'd, and which ones are really there? Maybe some have been deleted and set to your special value 0xdeadbeef, meaning deleted.
向量如何知道这里的哪些指针已被删除和 NULL 化,哪些是真正存在的?也许有些已被删除并设置为您的特殊值 0xdeadbeef,即已删除。
The point is the vector has no means to know this or know that its elements are pointers or locks or whatever. They just need to be things that have default constructors and are copyable, and meet the other such requirements that vector has on its elements.
关键是向量没有办法知道这一点或知道它的元素是指针或锁或其他任何东西。它们只需要具有默认构造函数并且是可复制的,并且满足 vector 对其元素的其他此类要求。
The solution is to be sure that whatever vector HOLDS needs to be responsible for its cleanup. This is called RAII-- Resource Allocation Is Initialization, more importantly here, Resource Destruction is Deallocation. With Our CLock example above, the answer is obvious, be sure to unlock when we're done!
解决方案是确保任何载体 HOLDS 需要负责其清理工作。这就是所谓的RAII——Resource Allocation Is Initialization,这里更重要的是Resource Destruction就是Deallocation。通过上面的 CLock 示例,答案很明显,完成后一定要解锁!
class CLock
{
...
~Clock()
{
if (locked)
{
Unlock();
}
}
}
But with pointers its not so obvious. The solution is to wrap up the pointer in a smart_ptr class. The most prolific of these are the boost family of smart poniters.
但是有了指针,它就不那么明显了。解决方案是将指针封装在 smart_ptr 类中。其中最多产的是智能 poniters的boost 系列。
class CSmartPointer<T>
{
CSmartPointer( T* rawPtr)
{
m_ptr = rawPtr;
}
~CSmartPointer()
{
delete m_ptr;
}
}
Additional features are brought into play with pointers such as reference counting, but the above example should give you the gist of the nature of the problem and how its typically solved.
其他功能与指针一起发挥作用,例如引用计数,但上面的示例应该可以让您了解问题的本质及其通常如何解决的要点。
回答by Artur Soler
I suppose that you talk about the std::vector and not about language arrays.
我想您谈论的是 std::vector 而不是语言数组。
- When a program crashes, the OS recovers its memory
- std::vector releases the memory that it allocates. If you are storing pointers, they will not be deleted.
- Vectors are created as any other variable, they are not in the heap only because they are vectors.
- 当程序崩溃时,操作系统会恢复其内存
- std::vector 释放它分配的内存。如果您正在存储指针,它们将不会被删除。
- 向量被创建为任何其他变量,它们不在堆中仅仅是因为它们是向量。
回答by RichieHindle
Any memory created by your program will be released when it exits. That's a feature of the Operating System, nothing to do with the programming language you're using.
您的程序创建的任何内存都将在退出时释放。这是操作系统的一个特性,与您使用的编程语言无关。
"every time I run my program I loose RAM" must be due to some other effect - how are you measuring that?
“每次我运行我的程序时,我都会丢失 RAM”一定是由于其他一些影响 - 你是如何衡量的?
As to why you'd use "new" - two reasons:
至于你为什么要使用“new”——两个原因:
- You want to control when they are freed
- You want them to persist after the current function exits.
- 你想控制他们什么时候被释放
- 您希望它们在当前函数退出后继续存在。
回答by T.E.D.
One of the two of us is a bit confused here.
我们两个中的一个在这里有点困惑。
If you are using std::vector, you don't need to manually allocate memory for its elements. Extra space will automaticly be allocated when needed whenever you do a push_back(). If you need all space preallocated for some reason, you can call reserve(). Either way, the memory gets freed automagically for you when the vector is destructed.
如果您使用 std::vector,则无需为其元素手动分配内存。每当您执行 push_back() 时,将在需要时自动分配额外空间。如果您出于某种原因需要预先分配所有空间,您可以调用reserve()。无论哪种方式,当向量被破坏时,内存都会自动为您释放。
If you are doing new std::vector, you are getting a pointer to the vector. That is no different than calling new on any other class. You create a pointer to an object of that class, and it will get destructed when you call delete. If you don't like that behavior, try creating your vector on the stack.
如果你在做新的 std::vector,你会得到一个指向向量的指针。这与在任何其他类上调用 new 没有什么不同。你创建了一个指向那个类的对象的指针,当你调用 delete 时它会被破坏。如果您不喜欢这种行为,请尝试在堆栈上创建您的向量。
回答by no-op
Another scenario not mentioned in regards to when you'd want to use "new", is in some cases when a vector is a member variable of a class. The NULL can be used as an additional semaphore, for example during create on demand; also, if the vector usage is sparsely populated on your class, then not even creating one unless it's really needed will save you memory, at the expense of the extra 4 byte penalty on all instances as well as the runtime penalty of the pointer indirection.
关于何时要使用“new”的另一个未提及的情况是,在某些情况下,向量是类的成员变量。NULL 可用作附加信号量,例如在按需创建期间;此外,如果您的类中的向量使用量很少,那么除非确实需要,否则即使不创建一个也可以节省您的内存,代价是所有实例的额外 4 字节损失以及指针间接的运行时损失。
回答by Alex Martelli
For the "lost memory", what @RichieHindie says.
对于“失去的记忆”,@RichieHindie 所说的。
For the second question:
对于第二个问题:
can vectors created without the NEW keyword really be left to their own devices and trusted to clear up after themselves even if code is aborted mid flow
没有 NEW 关键字创建的向量是否真的可以留给他们自己的设备并信任他们自己清理,即使代码在流程中中止
While normal program termination (including termination by exception) ensures that destructors execute (with some quibbles regarding those for static data -- in theory those should run too, in practice you might occasionally get problems), a sufficiently hard crash of the process cannot guarantee any behavior -- for example, a kill -9
is guaranteedto terminate your program ASAP, without giving it the chance to execute any destructors or anything else.
虽然正常的程序终止(包括异常终止)确保析构函数执行(对于静态数据的析构函数有一些争论——理论上那些也应该运行,实际上你可能偶尔会遇到问题),但进程的严重崩溃并不能保证任何行为-例如,一个kill -9
是保证,以尽快终止你的程序,没有给它执行任何析构函数或其他任何的机会。