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

C++拷贝构造函数未将字符复制到新动态内存位置原因咨询

C++ char*成员深拷贝异常问题分析

问题描述

在实现带char*类型成员的类的拷贝构造函数时,已显式为新对象的指针成员分配独立动态内存,但运行时观测到新旧对象的指针成员仍指向同一内存地址,修改其中一个对象的成员值会同步修改另一个对象的对应值,未达到深拷贝预期。
问题复现代码如下:

#include <iostream>

class Test{
public:
  char *c;

  Test(char a){
    c = new char();
    *c = a;
  }

  Test (const Test& obj){
    c = new char();
    this->c = obj.c; // 该行未达到预期效果
  }

  char getValue(){
    return *c;
  }

  void setValue(char a){
    *c = a;
  }

  char* getAddress(){
    std::cout << "Address is " << c << std::endl;
  }
};

int main()
{
  Test t1 ('a');
  Test t2 = t1;

  std::cout << "t1.c " << t1.getValue() << std::endl;
  std::cout << "t2.c " << t2.getValue() << std::endl;
  t1.getAddress();
  t2.getAddress();

  t2.setValue('z');

  std::cout << "t1.c " << t1.getValue() << std::endl;
  std::cout << "t2.c " << t2.getValue() << std::endl;
  t1.getAddress();
  t2.getAddress();

  return 0;
}

将拷贝构造函数内的赋值逻辑替换为strcpy后,可正常实现深拷贝,对应实现如下:

Test (const Test& obj){
    c = new char();
    strcpy(this->c, obj.c);
  }

根本原因

错误的核心是混淆了指针本身的赋值和指针指向内容的赋值:

  • 拷贝构造函数中第一行c = new char();确实为新对象申请了一块独立的堆内存,此时新对象的c指针存储的是这块新内存的起始地址。
  • 紧接着执行的this->c = obj.c;是指针变量的直接赋值:这行代码会把源对象obj.c存储的地址值,直接覆盖掉this->c里原本保存的新申请内存的地址。
    这行代码执行后会产生两个结果:
    • 刚申请的新堆内存没有任何指针指向,直接发生内存泄漏
    • 新对象的c和源对象的c存储了完全相同的地址,二者指向同一块堆内存,本质还是浅拷贝,修改其中一个指针指向的内容自然会影响另一个对象。

strcpy实现深拷贝的原理

strcpy操作的是指针指向的内存空间内容,不会修改指针本身存储的地址值:

  • 第一行c = new char();申请的新内存地址会一直保存在this->c中,不会被覆盖
  • strcpy会把源对象c指向内存中存储的字符数据,拷贝到新对象c指向的新分配内存中。此时两个指针分别指向两块独立的内存,只是内存中存储的内容一致,完全符合深拷贝的预期。

额外说明:示例代码里的getAddress函数存在实现缺陷:直接给cout传入char*指针时,标准库会将其识别为C风格字符串逐字符打印,由于代码只分配了1字节的char空间、没有预留字符串终止符\0的位置,会触发内存越界访问;同时该函数声明返回值为char*但没有写return语句,属于未定义行为。如果要打印指针保存的内存地址,需要把c强制转换为void*类型再输出。


内容的提问来源于stack exchange,提问作者Jayakumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 05:57:13