简体   繁体   English

C ++中的内存管理

[英]Memory Management in C++

I'm trying to test how and where the data is located and destroyed. 我正在尝试测试如何以及在何处定位和销毁数据。 For the example code below: 对于下面的示例代码:

  1. A new point is created and returned with NewCartesian method. 创建一个新点并使用NewCartesian方法返回。 I know that it should be stored in heap. 我知道它应该存储在堆中。 When it's pushed back into the vector, does the memory of the points content is copied into a new Point structure? 将其推回向量中时,是否将点内容的内存复制到新的Point结构中? Or is it stored as a reference the this pointer? 还是将此指针存储为参考?

  2. When the point is created, when is it destroyed? 创建点时,什么时候销毁它? Do I need to destroy the points when I'm done with it? 完成后是否需要销毁积分? Or are they destroyed when they are not usefuly anymore? 还是当它们不再有用时被销毁? For example, if main was another function, the vector would not be useful when it's finished. 例如,如果main是另一个函数,则向量完成后将不再有用。

  3. Depending on the answers above, when is it good to use the reference of objects? 根据上面的答案,什么时候使用对象的引用好? Should I use Point& p or Point p for the return of Point::NewCartesian? 我应该使用Point&p还是Point p来返回Point :: NewCartesian?

     #define _USE_MATH_DEFINES #include <iostream> #include <cmath> using namespace std; struct Point { private: Point(float x, float y) : x(x), y(y) {} public: float x, y; static Point NewCartesian(float x, float y) { return{ x, y }; } }; int main() { vector<Point> vectorPoint; for (int i = 0; i < 10000; i++) { Point& p = Point::NewCartesian(5, 10); vectorPoint.push_back( p ); // vectorPoint.push_back( Point::NewCartesian(5, 10) ); Point& p2 = Point::NewPolar(5, M_PI_4); } cout << "deneme" << endl; getchar(); return 0; } 

Thank you for your help, 谢谢您的帮助,

Cheers, 干杯,

... I know that it should be stored in heap. ...我知道它应该存储在堆中。

Firstly, please read this explanation of why it's preferable to talk about automatic and dynamic object lifetimes, rather than stack/heap. 首先,请阅读以下说明,为什么最好谈论自动动态对象生存期而不是堆栈/堆。

Secondly, that object is neither dynamically-allocated nor on the heap. 其次,该对象既不动态分配也不在堆上。 You can tell because dynamic allocation uses a new -expression, or a library function like malloc , calloc or possibly mmap . 您可以知道,因为动态分配使用new expression或malloccalloc或可能的mmap类的库函数。 If you don't have any of those (and you almost never should), it's not dynamic. 如果您没有任何一个(而且几乎从来没有),那么它就不是动态的。

You're returning something by value, so that thing's lifetime is definitely automatic. 您要按值返回某事物,因此该事物的生命周期绝对是自动的。

When the point is created, when is it destroyed? 创建点时,什么时候销毁它?

If you write the full set of copy/move constructors and assignment operators, plus a destructor, you can simply set breakpoints in them in the debugger and see where they get invoked. 如果编写了完整的复制/移动构造函数和赋值运算符以及一个析构函数,则可以在调试器中简单地在它们中设置断点并查看它们的调用位置。 Or, have them all print their this pointer and input arguments (ie, the source object being moved or copied from). 或者,让它们全部打印this指针和输入参数(即,从其移动或复制的源对象)。

However, since we know the object is automatic, the answer is easy - when it goes out of scope. 但是,由于我们知道对象是自动的,因此答案很简单-当它超出范围时。

Should I use Point& p or Point p for the return of Point::NewCartesian? 我应该使用Point&p还是Point p来返回Point :: NewCartesian?

Definitely the second: the first returns a reference to an object with automatic lifetime in the scope of the NewCartesian function, meaning the objected referred to is already dead by the time the caller gets the reference. 绝对是第二个:第一个返回对NewCartesian函数范围内具有自动生存期的对象的引用,这意味着在调用者获取引用时,所引用的对象已经死亡。

Finally, this code 最后,这段代码

Point& p = Point::NewCartesian(5, 10);

is weird - it makes it hard to determine the lifetime of the Point referred to by p by reading the code. 很奇怪-很难通过读取代码来确定p所指的Point的生存期。 It could be some static/global/other object with dynamic lifetime to which NewCartesian returns a reference, or (as is actually the case) you could be binding a reference to an anonymous temporary. NewCartesian可以将某个具有动态生存期的静态/全局/其他对象返回给其引用, 或者 (实际上)将引用绑定到匿名临时对象。 There's no benefit to writing it this way instead of 用这种方式代替它编写没有任何好处

Point p = Point::NewCartesian(5, 10);

or just passing the temporary straight to push_back as in your commented code. 或仅将临时笔直传递给push_back如您的注释代码中所示。


As an aside, the design of Point is very odd. 顺便说一句, Point的设计非常奇怪。 It has public data members, but a private constructor, and a public static method that just calls the constructor. 它具有公共数据成员,但具有私有构造函数,以及仅调用构造函数的公共静态方法。 You could omit the constructor and static method entirely and just use aggregate initialization, or omit the static method and make the constructor public. 您可以完全省略构造函数和静态方法,而只使用聚合初始化,也可以省略静态方法并使构造函数公开。

1a. 1a。 No, it's on the stack, but read the answer by Useless , why the terms stack and heap are not the best choice. 不,它在堆栈上,但请阅读Useless答案 ,为什么术语堆栈不是最佳选择。

1b. 1b。 It gets copied when you call push_back . 当您调用push_back时,它将被复制。

2 . 2。 It's destroyed immediately after being created, because it only exists within the scope of the NewCartesian call and for the duration of the return being evaluated. 它在创建后立即销毁,因为它仅存在于NewCartesian调用的范围内并且在评估返回的持续时间内。

3a. 3a。 You use a reference whenever you have a valid instance and want to pass it to a function without creating a copy. 只要有有效的实例,并且想将其传递给函数而不创建副本,就可以使用引用。 Specifically the function should have a reference parameter. 具体来说,该函数应具有参考参数。

3b. 3b。 You should use Point p , not Point& p , because right now you get a dangling reference to an object that doesn't exist anymore (see 2.) 您应该使用Point p ,而不是Point& p ,因为现在您可以悬空引用一个不再存在的对象(请参阅2.)。

As pointed out by Steven W. Klassen in the comments, your best option is the code that you have commented out: vectorPoint.push_back( Point::NewCartesian(5, 10) ); 正如史蒂文· vectorPoint.push_back( Point::NewCartesian(5, 10) ); Steven W. Klassen)在评论中指出的那样,最好的选择是注释掉的代码: vectorPoint.push_back( Point::NewCartesian(5, 10) ); . Passing the call to NewCartesian directly into push_back without making a separate local copy, allows the compiler to optimize it so that the memory is constructed exactly where push_back wants it and avoiding any intermediate memory allocations or copies. NewCartesian的调用直接传递到push_back而无需创建单独的本地副本,从而使编译器可以对其进行优化,以便在push_back精确地构造内存,并避免任何中间内存分配或副本。 (Or more technically, it allows it to use the move operator.) (或更确切地说,它允许它使用move运算符。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM