假设我定义了一些类:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
}
然后使用它编写一些代码.我为什么要执行以下操作?
Then write some code using it. Why would I do the following?
Pixel p;
p.x = 2;
p.y = 5;
来自 Java 世界,我一直在写:
Coming from a Java world I always write:
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
他们基本上做同样的事情,对吧?一个在堆栈上,而另一个在堆上,所以我稍后必须删除它.两者之间有什么根本区别吗?为什么我应该更喜欢一个?
They basically do the same thing, right? One is on the stack while the other is on the heap, so I'll have to delete it later on. Is there any fundamental difference between the two? Why should I prefer one over the other?
是的,一个在堆栈上,另一个在堆上.有两个重要区别:
Yes, one is on the stack, the other on the heap. There are two important differences:
delete
来避免它们,而是将其包装在堆栈分配的对象中,这些对象在内部调用 delete
,通常在它们的析构函数中.如果您尝试手动跟踪所有分配,并在正确的时间调用 delete
,我向您保证每 100 行代码至少会发生内存泄漏.delete
yourself, instead wrapping it in stack-allocated objects which call delete
internally, typicaly in their destructor. If you attempt to manually keep track of all allocations, and call delete
at the right times, I guarantee you that you'll have at least a memory leak per 100 lines of code.作为一个小例子,考虑以下代码:
As a small example, consider this code:
class Pixel {
public:
Pixel(){ x=0; y=0;};
int x;
int y;
};
void foo() {
Pixel* p = new Pixel();
p->x = 2;
p->y = 5;
bar();
delete p;
}
很无辜的代码,对吧?我们创建一个像素,然后调用一些不相关的函数,然后删除该像素.是否存在内存泄漏?
Pretty innocent code, right? We create a pixel, then we call some unrelated function, and then we delete the pixel. Is there a memory leak?
答案是可能".如果 bar
抛出异常会发生什么?delete
永远不会被调用,像素永远不会被删除,我们会泄漏内存.现在考虑这个:
And the answer is "possibly". What happens if bar
throws an exception? delete
never gets called, the pixel is never deleted, and we leak memory. Now consider this:
void foo() {
Pixel p;
p.x = 2;
p.y = 5;
bar();
}
这不会泄漏内存.当然,在这个简单的例子中,一切都在堆栈上,所以它会自动清理,但即使 Pixel
类在内部进行了动态分配,也不会泄漏.Pixel
类将简单地被赋予一个析构函数来删除它,无论我们如何离开 foo
函数,都会调用这个析构函数.即使我们因为 bar
抛出异常而离开它.以下稍微做作的示例显示了这一点:
This won't leak memory. Of course in this simple case, everything is on the stack, so it gets cleaned up automatically, but even if the Pixel
class had made a dynamic allocation internally, that wouldn't leak either. The Pixel
class would simply be given a destructor that deletes it, and this destructor would be called no matter how we leave the foo
function. Even if we leave it because bar
threw an exception. The following, slightly contrived example shows this:
class Pixel {
public:
Pixel(){ x=new int(0); y=new int(0);};
int* x;
int* y;
~Pixel() {
delete x;
delete y;
}
};
void foo() {
Pixel p;
*p.x = 2;
*p.y = 5;
bar();
}
Pixel 类现在在内部分配了一些堆内存,但是它的析构函数负责清理它,所以当使用这个类时,我们不必担心它.(我应该提一下,这里的最后一个例子被简化了很多,以显示一般原则.如果我们实际使用这个类,它也包含几个可能的错误.如果 y 的分配失败,x 永远不会被释放, 如果 Pixel 被复制,我们最终会导致两个实例都试图删除相同的数据.因此,请保留最后一个示例.实际代码有点棘手,但它显示了总体思路)
The Pixel class now internally allocates some heap memory, but its destructor takes care of cleaning it up, so when using the class, we don't have to worry about it. (I should probably mention that the last example here is simplified a lot, in order to show the general principle. If we were to actually use this class, it contains several possible errors too. If the allocation of y fails, x never gets freed, and if the Pixel gets copied, we end up with both instances trying to delete the same data. So take the final example here with a grain of salt. Real-world code is a bit trickier, but it shows the general idea)
当然,相同的技术可以扩展到内存分配以外的其他资源.例如,它可用于保证文件或数据库连接在使用后关闭,或者释放线程代码的同步锁.
Of course the same technique can be extended to other resources than memory allocations. For example it can be used to guarantee that files or database connections are closed after use, or that synchronization locks for your threading code are released.
这篇关于为什么不在 C++ 中对所有内容都使用指针?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!