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

含分配指针的类的拷贝构造正确实现及浅拷贝问题求解

问题描述

我有一个包含动态分配指针的类(示例中简化为1个指针),希望调用拷贝构造时无需执行深拷贝。该类定义如下:

class Example {
    public:
    Example() : ptr1(0), len1(0) {} 
    Example(const Example& other) : ptr1(0), len1(0) {
        if (other.ptr1) {
            ptr1 = other.ptr1;
            len1 = other.len1;
        }
    }
    ~Example() {
        if (ptr1)
            delete[] ptr1;
    }
    char* ptr1;
    int len1;
};

当创建该类实例、分配指针后插入到函数外作用域的容器时,会出现合理的use after free问题:

// some function
{
    Example a;
    a.ptr1 = new char[1];
    vec.push_back(a); // 注:vec是函数外创建的std::vector<Example>
}

我知道深拷贝可以解决此问题,或插入空实例后操作容器中保存的拷贝,但想了解C++11标准下是否有更多解决方案。

C++11下的替代解决方案

1. 实现移动语义转移资源所有权

C++11的移动语义可以直接转移资源所有权,避免拷贝操作。需要为Example类添加移动构造函数和移动赋值运算符:

// 移动构造函数
Example(Example&& other) noexcept : ptr1(other.ptr1), len1(other.len1) {
    // 清空源对象指针,防止其析构时释放资源
    other.ptr1 = nullptr;
    other.len1 = 0;
}

// 移动赋值运算符
Example& operator=(Example&& other) noexcept {
    if (this != &other) {
        // 释放当前对象已有资源
        if (ptr1) delete[] ptr1;
        // 转移源对象的资源所有权
        ptr1 = other.ptr1;
        len1 = other.len1;
        // 清空源对象
        other.ptr1 = nullptr;
        other.len1 = 0;
    }
    return *this;
}

使用时通过std::move将局部对象的资源转移给容器元素:

vec.push_back(std::move(a));

此时局部对象a析构时,因指针已被置空不会释放资源,容器中的对象持有资源所有权,彻底避免double free和use after free问题。

2. 用智能指针替代裸指针

C++11提供的智能指针可以自动管理资源生命周期,无需手动编写析构、拷贝/移动逻辑:

  • 共享资源场景:用std::shared_ptr,拷贝时自动维护引用计数,只有最后一个持有资源的对象析构时才释放内存:
#include <memory>

class Example {
public:
    Example() : len1(0) {} 
    Example(const Example& other) = default;
    ~Example() = default;

    std::shared_ptr<char[]> ptr1;
    int len1;
};
  • 独占资源场景:用std::unique_ptr,禁用拷贝操作,只能通过移动语义转移所有权:
#include <memory>

class Example {
public:
    Example() : len1(0) {} 
    // 禁用拷贝构造和赋值
    Example(const Example& other) = delete;
    Example& operator=(const Example& other) = delete;
    // 默认生成移动构造和赋值
    Example(Example&& other) = default;
    Example& operator=(Example&& other) = default;
    ~Example() = default;

    std::unique_ptr<char[]> ptr1;
    int len1;
};

插入容器时同样用std::move转移所有权:

vec.push_back(std::move(a));

3. 直接在容器内构造对象

使用emplace_back直接在容器的内存空间中构造Example对象,跳过局部对象的创建和析构过程:

// 为Example添加带参数的构造函数简化操作
Example(int length) : len1(length) {
    ptr1 = length > 0 ? new char[length] : nullptr;
}

// 直接在容器中构造对象
vec.emplace_back(1); // 构造一个len1=1、ptr1指向new char[1]的Example对象

这种方式从根源上避免了资源所有权转移的问题,无需处理局部对象的析构。

内容的提问来源于stack exchange,提问作者carce-bo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 04:40:24