C++自定义String类:赋值运算符调用时拷贝构造函数为何也被触发?
为什么赋值运算符调用时会触发拷贝构造函数?
你的代码确实存在问题,同时对赋值运算符的返回值设计理解有偏差,这两个原因共同导致了拷贝构造函数被额外调用。
1. 拷贝构造被触发的直接原因:赋值运算符返回值是值类型
你的赋值运算符声明是:
String_Overload operator=(String_Overload& s_ptr_cpy)
返回的是值类型而非引用类型。当执行return *this;时,会调用拷贝构造函数把*this拷贝到临时对象中再返回——这就是输出里最后一行In copy constructor的来源。
C++中赋值运算符的标准写法是返回非const引用,既可以避免不必要的拷贝,还支持链式赋值(比如s4 = s3 = s2)。正确声明应为:
String_Overload& operator=(const String_Overload& s_ptr_cpy)
2. 代码里的其他严重问题
除了返回值的问题,你的代码还有多个会触发未定义行为的错误:
- 字符串结束符位置错误:所有构造函数和赋值运算符中,你把
'\0'写到了s_ptr[len+1],但数组下标从0开始,长度为len+1的数组有效下标是0~len,结束符应写到s_ptr[len],否则会越界访问。 - 默认构造函数内存分配错误:
new char(1)是分配单个字符并初始化为1,而非分配大小为1的字符数组,应改成new char[1],否则后续delete []s_ptr会触发未定义行为。 - 赋值运算符未释放原有内存:如果当前对象的
s_ptr内存小于要赋值的字符串长度,直接写入会导致缓冲区溢出,正确做法是先释放原有内存,再重新分配足够空间。 - 赋值运算符参数未加const:参数应为
const String_Overload&,这样才能接受const对象或临时对象的赋值,符合C++常量规范。
修正后的完整代码
#include<iostream> using namespace std; class String_Overload{ char *s_ptr; public: String_Overload() { s_ptr = new char[1]; // 修正:分配数组而非单个字符 s_ptr[0] = '\0'; cout << "In no param constructor\n"; } String_Overload(const char* s_ptr_cpy) { int len = 0; while(s_ptr_cpy[len] != '\0') {++len;} // 用'\0'代替NULL更规范 s_ptr = new char[len + 1]; for(int i=0; i<len; i++) { s_ptr[i] = s_ptr_cpy[i]; } s_ptr[len] = '\0'; // 修正:结束符位置正确 cout << "In overloaded constructor\n"; } String_Overload(const String_Overload& s_ptr_cpy) { int len = 0; while(s_ptr_cpy.s_ptr[len] != '\0') {++len;} s_ptr = new char[len + 1]; for(int i=0; i<len; i++) { s_ptr[i] = s_ptr_cpy.s_ptr[i]; } s_ptr[len] = '\0'; // 修正:结束符位置正确 cout << "In copy constructor\n"; } // 修正:返回引用,参数为const引用 String_Overload& operator=(const String_Overload& s_ptr_cpy) { // 防止自赋值 if(this == &s_ptr_cpy) return *this; // 释放原有内存 delete [] s_ptr; // 重新分配空间并拷贝 int len = 0; while(s_ptr_cpy.s_ptr[len] != '\0') {++len;} s_ptr = new char[len + 1]; for(int i=0; i<len; i++) { s_ptr[i] = s_ptr_cpy.s_ptr[i]; } s_ptr[len] = '\0'; // 修正:结束符位置正确 cout << "In assignment operator\n"; return *this; } void display(){cout << s_ptr << "\n";} ~String_Overload(){delete []s_ptr;} }; int main() { char temp[] = "Hello World"; String_Overload s1{temp}; String_Overload s4; s4 = s1; s4.display(); return 0; }
修正后的输出
In overloaded constructor In no param constructor In assignment operator Hello World
此时只会调用赋值运算符,不会触发额外的拷贝构造。
内容的提问来源于stack exchange,提问作者user3395789
相关产品推荐
相关产品推荐

