堆对象问题和RAII建议请求 [英] heap object question, and RAII advice request

查看:62
本文介绍了堆对象问题和RAII建议请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好,

我仍​​然在学习如何编写体面的C ++代码。我将不胜感激任何好的建议或更正。我有两个问题,一个是技术问题,一个是关于如何设计我的代码的建议。


1.我在某处读过(不记得了,一定是一些教程页面) )只能通过指针访问堆上分配的对象。因此,例如

Hi all,
I am still in the process of lerning how to write decent C++ code. I will appreciate any good advice or corrections. I have two questions, a technical one and one for advice for how to design my code.

1. I have read somewhere (can''t remember, must have been some tutorial page) that objects allocated on the heap can only be accessed through pointers. Thus, for example

展开 | 选择 < span class =codeDivider> | Wrap | 行号

推荐答案


1我已经读过某个地方(不记得,一定是一些教程页面),堆上分配的对象只能通过指针访问。因此,例如

展开|选择|换行|行号向量< int> * v_ptr = new vector< int>(100);

这里v_ptr指向生活在堆上的100个整数的向量。

我可以通过v_ptr-> at(4)访问向量的条目;或(* v_ptr)[4] 。 (是否有其他方式来访问条目?)
1. I have read somewhere (can''t remember, must have been some tutorial page) that objects allocated on the heap can only be accessed through pointers. Thus, for example
Expand|Select|Wrap|Line Numbers vector<int> * v_ptr = new vector<int>(100);
Here v_ptr points to a vector of 100 integers living on the heap.
I can access the entries of the vector via "v_ptr->at(4)" or "(*v_ptr)[4]" . (Is there another way to access the entries?)



数组的名称是元素0的地址。因此。 v_ptr确实是& v_ptr [0]。因此,您可以像访问任何其他数组一样以v_ptr [4]的形式访问数组元素。请记住,向量必须实现为数组。


The name of an array is the address of element 0. Therefore. v_ptr is really &v_ptr[0]. So, you can access your array elements as v_ptr[4] exactly as you would for any other array. Remember, a vector must be implemented as an array.



我可以尝试使用堆内容填充本地向量变量,例如

展开|选择|换行|行号向量< int> v = *(new vector< int>(100));

但如果我理解正确的话,这将首先在堆上创建一个包含100个整数的向量对象,取其指针,取消引用它,然后在堆栈上构建另一个向量对象(命名为v)一个在堆上使用复制构造函数。因此,这将导致立即内存泄漏,因为无法再对该指针调用delete。 (我理解这一点是正确的吗?)
I could try to fill a local vector variable with heap contents like
Expand|Select|Wrap|Line Numbers vector<int> v = *(new vector<int>(100));
but if I understand correctly, this will first create a vector object with 100 integers on the heap, take its pointer, dereference it, and then construct ANOTHER vector object on the stack (named v) from the one on the heap using the copy constructor. Thus, this would lead to an immediate memory leak, since there is no way to call delete on that pointer any more. (Am I understanding this correctly?)



从编译器的角度看这个。首先,通过调用向量构造函数创建100个int的堆向量。其次,创建第二个向量(v)作为堆向量的副本。编译器已完成。


但是,您无法捕获堆向量的地址。它现在丢失了,你永远不能删除它。 永远不要这样做。

Look as this from the compiler''s point of view. First, create a heap vector of 100 ints by a call to a vector constructor. Second, create a second vector (v) as a copy of the heap vector. The compiler is done.

However, you failed to capture the address opf the heap vector. It is now lost and you can never delete it. Do not ever to do this.


现在,我的问题:如果我输入会发生什么

展开|选择|换行|行号向量< int>鞋面; = *(new vector< int>(100));

这里有没有我无法看到的复制品吗?或者我真的只在堆上构建了一个向量,我现在可以像v [4]那样访问它。 ,我可以稍后用delete& v;删除它。 ?
Now, my question: What will happens if I type
Expand|Select|Wrap|Line Numbers vector<int> v& = *(new vector<int>(100));
Is there any copying going on here that I can''t see? Or have I really constructed only one vector on the heap, which I can now access like "v[4]" , and which I can delete later on with "delete &v;" ?



No.不幸的是,v现在是对向量的引用,而不是向量指针。问题:如何知道这个特定的引用是指一个堆对象?也就是说,你将如何删除堆对象。再说一次,不要这样做。


我建议你查看本网站上的C见解,获取有关Handle Class或智能指针的文章。我想你会对你在那里读到的内容感到非常满意。

No. Unforunately, v is now a reference to a vector rather than being a vector pointer. Question: How to you know this particular reference refers to a heap object? That is, how will you ever delete the heap object. Again, do not ever do this.

I suggest you look in the C insights on this web site for an article on the Handle Class, or smart pointer. I think you will be very pleased with what you read there.


2.虽然第一个问题只是关于理解代码我还有另一个问题我的代码设计方式。我已经阅读了以下建议:

除非必须,否则不要在堆上分配变量(如果您需要创建范围之外的数据,或者如果没有堆栈上有足够的空间)。
2. While the first question was just about understanding the code I have another one concerning my way of code design. I have read the following advice:
Don''t allocate variables on the heap unless you have to (in case you need the data outside of the scope it was created in, or in case there is not enough space on the stack).



这只是倒退。除非必须,否则规则是永远不要使用堆栈。想一想。在堆栈上,编译器控制对象的生命而不是你。这意味着编译器可以在未经您同意的情况下删除该对象,并且在编译时它是如何知道它正在删除对象的最后一个实例并且程序中的其他指针没有指向该对象的指针?答:它没有。


你可以在C ++程序中做的最危险的事情是传递指针。顺便说一句:你有没有看过关于Handle Class的C见解文章了吗?这个问题在那里得到解答。

This is just backwards. The rule is to NEVER use the stack unless you have to. Think about it. On the stack thje compiler controls the life of the object rather than you. That means the compiler can delete the object without your consent and when it does how does the compiler know it is deleting the last instance of the object and that there aren''t pointers elsewhere in the program that point to this object? Answer: It doesn''t.

The single most dangerous thing you can do in a C++ program is pass pointers around. BTW: Have you read that C insights article on the Handle Class yet? This question is answered there.


如果使用new分配内存运算符,然后遵循RAII原则,在堆栈上使用一些包装器对象(如std :: auto_ptr),为你做删除,这样就不会有内存泄漏。
If you allocate memory using the "new" operator, then follow the RAII principle, make use of some wrapper objects (like std::auto_ptr) on the stack that will do the deleting for you, so that there will be no memory leaks.



这很傻。阅读Handle Class文章。

This is silly. Read that Handle Class article.


现在,我处理的情况是我必须编写接收大量向量的函数(通常是复数并生产其中几种。并且这些矢量可以具有相当大的尺寸。我需要我的代码来处理包含1,000,000个条目的向量。

现在我的问题:

使用堆是否是正确的选择(使用new创建向量)在这种情况下,即使我需要的对象只是我所在的范围?
Now, I am in the situation that I have to write functions that receive a number of vectors (normally of complex numbers) and produce several of them. And these vectors can have a pretty large size. I need my code to work with vectors with 1,000,000 entries.
Now my questions:
Is it the right choice to use the heap (create vectors using "new") in this case, even if I need the objects just for the scope I am in?



是的,实际上你必须使用堆。由于堆栈溢出,你不能让你的程序崩溃。您必须保持对数据的控制而不是将其留给编译器。

Yes, in fact you must use the heap. You can''t afford to crash your program due to stack overflow. You have to maintain control of your data and not leave it to the compiler.


如果我想要一个函数返回多个向量对象,我会在调用函数之前创建一个,然后调用它为它提供一个引用(或指针)到该向量,以便它可以写入它。使用std :: auto_ptr时,我该如何做到最好?我不能只将auto_ptr作为参数给函数,因为这样会在返回时删除向量。
If I want a function to return more than one vector object, I would create one before calling the function and than call it providing it with a reference (or pointer) to that vector so that it can write to it. How do I do this best when using "std::auto_ptr"s ? I can''t just give the auto_ptr as a parameter to the function because then the vector will be deleted on return.



你不想返回一个向量,因为副本将被返回。您希望返回指向该向量或句柄类对象的指针。请阅读该文章。


接下来,永远不要使用auto_ptr。它并不像你想象的那样工作。请参阅Scott Meyers的书Effective STL。

You don''t want to return a vector because a copy will be made to return. You want to return a pointer to that vector, or a handle class object. Please read that article.

Next, NEVER use auto_ptr. It doesn''t work the way you think. Refer to Scott Meyers book "Effective STL".


我非常感谢您必须说的任何有用的内容。
I would greatly appreciate anything useful you would have to say.



我希望这会有所帮助。

I hope this helps.



想一想。在堆栈上,编译器控制对象的生命而不是你。这意味着编译器可以在未经您同意的情况下删除该对象,并且在编译时它是如何知道它正在删除对象的最后一个实例并且程序中的其他指针没有指向该对象的指针?答:不是。
Think about it. On the stack thje compiler controls the life of the object rather than you. That means the compiler can delete the object without your consent and when it does how does the compiler know it is deleting the last instance of the object and that there aren''t pointers elsewhere in the program that point to this object? Answer: It doesn''t.



这并非严格来说,编译器不控制C ++标准所做的堆栈变量的生命周期(假设您使用的是标准兼容的编译器,如果你然后得到一个新的编译器)因为这些变量有自动存储类,标准清楚地列出了该存储类的变量应该如何运行。


你可以依赖于声明的变量在堆栈上将存在以及什么时候它将被删除(或者至少当你应该停止使用它因为它可能被删除)。


关于编译器删除堆栈对象的事情不知道所有指向它的指针是否已被停止使用都是无稽之谈,因为对于堆来说它也是如此,它只是用户拥有控制权。在删除对象之后,程序员编写存储基于堆栈的对象的指针的代码与在用户删除对象之后存储指向基于堆的对象的指针的程序员处于相同的错误类中。在这两种情况下,程序员所讨论的对象具有已知的生命周期,并且程序员在删除它之后尝试使用它。


presencia请理解我实际上不同意什么弱智人士说,只有他所说的庄园,根据我的喜好,它有点过于切割和干燥。编程不是那样的,所有弱点写的都是合理的经验法则,如果遵循它会在90-95%的时间内给你正确的东西。但重要的是要了解导致这些经验法则的基本机制,以便您可以知道它们什么时候不适用。


另外这些经验法则不是适用于您不需要时可以操作的每个平台。例如,嵌入式项目禁止使用堆的情况并不少见,或者至少只允许非常有限的使用,但许多C ++程序员将堆视为无限的资源。养成遵循这些经验法则的习惯,你冒着以同样方式思考的风险,因为这些经验法则假设一个相对较大的堆和一个相对较小的堆栈,但对于每个平台而言都是如此。


在C见解中绝对阅读Handle Class / smart指针,这是处理许多与知道何时删除指针有关的问题的一种非常聪明的方法。


有趣的是我最近使用过auto_ptr但只是以非常有限的方式。它肯定不是句柄类的替代。

That is not strictly true, the compiler does not control the lifetime of variables on the stack the C++ standard does (assuming you are using a standard compliant compiler and if you are then get a new compiler) since those variables have auto storage-class and the standard sets out clearly how variables with that storage class should operate.

You can rely on when a variable declared on the stack will exist and when it will be deleted (or at least when you should stop using it because it may be deleted).

And the thing about the compiler deleting a stack object without knowing if all pointers to it have stopped being used is nonsense because the same is true for a heap it its just that the user has control. The programmer writing code that stores the pointer of a stack based object after the object has been deleted is in the same class of error as the programmer storing a pointer to a heap based object after the user has deleted the object. In both cases the programmer the object in question had a know lifetime and the programmer attempted to use it after it was deleted.

presencia please understand that I don''t actually disagree with what weaknessforcats has said, only the manor in which he says it which for my liking is a little too cut and dried. Programming is not like that, everything weaknessforcats has written are reasonable rules of thumb which if followed will give you the right thing 90-95% of the time. But it is important to understand the underlying mechanisms that result in those rules of thumb so that you can know when they don''t apply.

Also those rules of thumb don''t apply to every platform you need to be able to operate when they don''t apply. For instance it is not uncommon for embedded projects to forbid the use of the heap or at the very least only allow very limited use but many C++ programmers treat the heap as if it were an unlimited resource. Get into the habit of following these rules of thumb and you run the risk of ending up thinking the same way because those rules of thumb assume a relatively large heap and a relatively small stack but that is just not true of every platform.

Definitely read the Handle Class/smart pointer in the C insights it is a very smart way of dealing with a lot of the issues related to knowing when to delete a pointer.

Interestingly I have used auto_ptr recently but only in a very limited way. It is certainly no replacement for a handle class.



你可以依赖堆栈上声明的变量何时存在以及何时存在被删除(或至少当你应该停止使用它,因为它可能被删除)。
You can rely on when a variable declared on the stack will exist and when it will be deleted (or at least when you should stop using it because it may be deleted).



这不是真的。


将指向堆栈变量的指针传递给函数。该函数使用在调用时收到的指针更新全局指针并返回。然后带有堆栈变量的函数返回。现在全局指针指向已删除的内存。然后你使用全局指针崩溃。


你可以从不依赖指针的目标在你使用指针时存在。


这个scenarion也适用于涉及多个线程的地方。

This is not true.

You pass a pointer to a stack variable to a function. That function updates a global pointer with the pointer it received on the call and returns. Then the function with the stack variable returns. Now the global pointer points to deleted memory. Then you crash using the global pointer.

You can never rely on the target of a pointer to exist at the time you use the pointer.

This scenarion also works where multiple threads are involved.


关于编译器删除a的事情堆栈对象,不知道它的所有指针是否已经停止使用都是无意义的,因为对于堆只有用户拥有控制权的情况也是如此。
And the thing about the compiler deleting a stack object without knowing if all pointers to it have stopped being used is nonsense because the same is true for a heap it its just that the user has control.



上面的例子反驳了这个陈述。对于堆的转换,同样的事情也不是这样。在exanple中,只删除指向堆对象的指针(因为它在堆栈上),但对象本身仍然存在,并且全局指针仍然有效。


再次,我说无论后果如何,编译器在超出范围时都会删除堆栈变量。你真的需要实现引用计数,这就是Handle对象发挥作用的地方。只是将裸指针传递给程序是你可以做的最危险的事情。

The above example disproves this statement. And the same thing is not true for a heap obeuct. Inthe exanple, only the pointer to the heap object is deleted (since it is on the stack) but the object itself still exists and the global pointer is still valid.

Again, I say the compiler deletes stack variables when they go out of scope regardless of consequences. You really need to implement reference counting and this is where the Handle object comes into play. Just passing naked pointer around a program is trhe most dangerous thing you can do.


这篇关于堆对象问题和RAII建议请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆