C++中Point类求和函数返回方式及拷贝构造函数调用疑问
嘿,咱们一步步拆解你的问题,把这些C++里的细节讲明白~
SumPoints写法有问题! 首先得指出,你的函数参数是Point& p1(引用类型),但代码里用了p1->x——这是指针的访问方式,引用应该用.,正确的写法应该是:
Point SumPoints(Point& p1, Point& p2) { Point result(p1.x + p2.x, p1.y + p2.y); return result; }
那为什么要这么写?核心原因是用引用参数避免不必要的拷贝:如果参数写成Point p1(传值),调用函数时会触发拷贝构造函数,把传入的Point对象复制一份到函数栈里;而用引用Point& p1,直接操作原对象,完全没有拷贝开销,这是很常见的优化手段。
答案是:绝对不推荐这么做,反而会带来严重问题。
如果你想返回指向result的指针,比如写成:
Point* SumPoints(Point& p1, Point& p2) { Point result(p1.x + p2.x, p1.y + p2.y); return &result; }
这会返回一个野指针——因为result是函数内的局部对象,函数执行完毕后,栈上的result会被销毁,指针指向的内存已经无效,后续访问这个指针会导致未定义行为(程序崩溃、乱码都有可能)。
那如果用new动态分配内存呢?比如:
Point* SumPoints(Point& p1, Point& p2) { return new Point(p1.x + p2.x, p1.y + p2.y); }
这确实能避免局部对象销毁的问题,但你必须手动调用delete释放内存,一旦忘记就会造成内存泄漏;而且动态分配内存的开销比栈上分配大得多,还要额外管理指针,反而比返回值更麻烦、效率更低。
另外要告诉你一个关键知识点:现代C++的返回值优化(RVO/NRVO)。当你返回局部对象时,编译器会直接把result构造到调用者(比如main函数)的目标对象里,完全不会触发拷贝构造函数,相当于直接在main的栈空间里创建结果对象,效率和返回指针一样高,还没有内存管理的风险。
=都会触发! 拷贝构造函数的作用是用一个已存在的对象创建一个新对象,它的触发场景是这些:
- 用一个对象初始化另一个新对象:
Point p2(p1);或者Point p2 = p1;(注意这是初始化,不是赋值) - 函数传值参数时:
void func(Point p),调用时会拷贝实参到形参p - 函数返回对象时(如果编译器没做RVO优化的话)
而你说的=,分两种情况:
- 初始化时的
=:比如Point p2 = p1;,这是拷贝初始化,会调用拷贝构造函数 - 赋值操作的
=:比如Point p2; p2 = p1;,这是给已经存在的p2赋值,调用的是赋值运算符重载(operator=),和拷贝构造函数没关系
总结一下:只有当=是用来创建新对象的时候,才会触发拷贝构造函数;如果是给已存在的对象赋值,触发的是赋值运算符。
内容的提问来源于stack exchange,提问作者user13575381

