c++ 深拷贝之 std::string 与 char*
✅ 方法 1:最简单、最安全(推荐)
HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), // 直接拷贝构造i(hp.i) { }
👉 让
std::string
自己处理复制,安全高效。
✅ 方法 2:如果你坚持要用
memcpy
(教学目的)HasPtr(const HasPtr& hp) : i(hp.i) {// 1. 获取原字符串内容和长度const char* src = hp.ps->c_str(); // 原字符串首地址size_t len = hp.ps->size(); // 长度// 2. 分配新内存(用于存储字符)char* buffer = new char[len + 1]; // +1 for '\0'// 3. 使用 memcpy 复制字符memcpy(buffer, src, len + 1); // 包括 '\0'// 4. 创建新的 std::string 并赋值给 psps = new std::string(buffer, len); // 用字符数组构造 string// 5. 清理临时 bufferdelete[] buffer; }
但这多此一举,因为
std::string
已经能很好拷贝自己。
⚠️ 更危险但“纯 C 风格”做法(不推荐)
如果你的类是:
class CString {char* data; public:CString(const char* s);CString(const CString& other);~CString(); };
那么可以用
memcpy
实现深拷贝:CString::CString(const CString& other) {size_t len = strlen(other.data);data = new char[len + 1];memcpy(data, other.data, len + 1); // ✅ 正确:目标在前,源在后 }
这才是
memcpy
的合理使用场景。
📊 三、
memcpy
在 C++ 中使用频率?
场景 是否常用 说明 C++ 类对象 ❌ 极少 会绕过构造函数,危险 POD 结构体 ✅ 有时 如 struct Point { int x,y; }
字节数组/缓冲区 ✅ 常用 网络、文件、图像处理 性能敏感代码 ✅ 有时 已知长度时比 strcpy
快std::string
,vector
等❌ 从不 用其自带方法 ✅ 正确使用
memcpy
的条件:
- 操作的是原始字节
- 知道确切长度
- 不涉及 C++ 对象构造/析构
- 性能关键路径
✅ 四、总结与建议
✅ 最终正确版本(推荐)
class HasPtr { public:HasPtr(const std::string& s = "") : ps(new std::string(s)), i(0) {}// ✅ 拷贝构造:深拷贝HasPtr(const HasPtr& hp) : ps(new std::string(*hp.ps)), // 简洁、安全、高效i(hp.i) { }// ✅ 拷贝赋值HasPtr& operator=(const HasPtr& hp) {if (this != &hp) {delete ps;ps = new std::string(*hp.ps);i = hp.i;}return *this;}// ✅ 析构~HasPtr() {delete ps;}private:std::string* ps;int i; };
📣 关键结论
问题 回答 你的代码可以吗? ❌ 不可以,有多个严重错误 能用 memcpy
吗?✅ 可以,但只适用于原始字符数组,不是 std::string
memcpy
在 C++ 常用吗?⚠️ 有限使用:仅用于性能关键的字节操作,不用在 C++ 对象上 推荐做法? 使用 std::string
的拷贝构造,或值语义(std::string ps
)
💡 最佳实践建议
- 优先使用值语义:
std::string ps
而不是std::string* ps
- 避免裸指针:用
std::unique_ptr
,std::shared_ptr
- 不要滥用
memcpy
:它是 C 工具,C++ 有更安全的方式- 理解工具边界:
memcpy
≠ 深拷贝,它只是一个字节复制函数👏 你已经触及了 C++ 资源管理的核心矛盾:手动控制 vs 安全抽象。继续这样深入思考,你会成为真正的 C++ 高手!