You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 11:07:10