我正在尝试测试数据的定位和销毁方式和位置。对于以下示例代码:
#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;
}
谢谢您的帮助,
干杯,
1A。不,它在堆栈上,但是通过answer读取Useless,为什么术语堆栈和堆不是最佳选择。
1B。当你调用push_back
时它会被复制。
2。它在创建后立即被销毁,因为它只存在于NewCartesian
调用的范围内并且在评估返回的持续时间内。
3A。只要有了有效的实例,并且想要将其传递给函数而不创建副本,就可以使用引用。具体来说,该函数应该有一个参考参数。
3B。你应该使用Point p
,而不是Point& p
,因为现在你得到一个不再存在的对象的悬空引用(见2.)
正如Steven W. Klassen在评论中指出的那样,您最好的选择是您注释掉的代码:vectorPoint.push_back( Point::NewCartesian(5, 10) );
。将调用NewCartesian
直接传递到push_back
而不制作单独的本地副本,允许编译器对其进行优化,以便在push_back
想要它的地方构建内存并避免任何中间内存分配或复制。 (或者从技术上讲,它允许它使用移动运算符。)
...我知道它应该存储在堆中。
首先,请read this解释为什么讨论自动和动态对象生命周期更好,而不是堆栈/堆。
其次,该对象既不是动态分配的,也不是堆上的。你可以说,因为动态分配使用new
表达式,或者像malloc
,calloc
或者mmap
这样的库函数。如果你没有任何这些(你几乎从不应该),那它就不是动态的。
你是按价值归还的,所以这个东西的生命周期绝对是自动的。
当点被创建时,它什么时候被破坏?
如果编写完整的复制/移动构造函数和赋值运算符以及析构函数,只需在调试器中设置断点并查看它们的调用位置即可。或者,让他们都打印他们的this
指针和输入参数(即,移动或复制源对象)。
但是,由于我们知道对象是自动的,所以答案很简单 - 当它超出范围时。
我应该使用Point&p或Point p来返回Point :: NewCartesian吗?
绝对是第二个:第一个返回对NewCartesian
函数范围内具有自动生命周期的对象的引用,这意味着在调用者获取引用时,被引用的被引用已经死亡。
最后,这段代码
Point& p = Point::NewCartesian(5, 10);
很奇怪 - 通过阅读代码很难确定Point
提到的p
的寿命。它可能是一些具有动态生命周期的静态/全局/其他对象,NewCartesian
返回一个引用,或者(实际上就是这种情况)您可以绑定对匿名临时的引用。以这种方式编写它没有任何好处,而不是
Point p = Point::NewCartesian(5, 10);
或者只是将临时直接传递给push_back
,如评论代码中所示。
顺便说一下,Point
的设计很奇怪。它有公共数据成员,但是私有构造函数和只调用构造函数的公共静态方法。您可以完全省略构造函数和静态方法,只使用聚合初始化,或省略静态方法并使构造函数公开。