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

如何为动态数组或uni_ptr编写移动构造函数与移动赋值运算符

问题1:移动构造函数与移动赋值运算符实现

你原有代码的移动语义核心思路是正确的,核心就是转移动态数组的所有权、将被移动对象的指针置空避免双重释放,只需修正原有代码的几处错误即可:

  • 构造函数中std::fill的结束指针计算错误:指针算术以元素为单位,不需要乘以sizeof(Tile),且原有代码存在笔误漏写了_cols_和sizeof之间的乘号
  • 拷贝赋值运算符漏写返回值类型Grid&,且未提前释放原有数组,存在内存泄漏
  • 移动赋值运算符未做自赋值校验,自赋值场景下会提前释放数组导致异常
  • 原有代码漏写析构函数释放动态数组,会造成内存泄漏

修正后的完整移动相关代码如下:

// 移动构造函数(size_t是基础类型,std::move可省略不影响逻辑)
Grid(Grid &&other) noexcept
    : _rows_(other._rows_),
      _cols_(other._cols_),
      _initialTile_(other._initialTile_),
      mytiles(other.mytiles)
{
    // 清空被移动对象,避免双重释放
    other.mytiles = nullptr;
    other._rows_ = other._cols_ = 0;
}

// 移动赋值运算符(补充自赋值校验)
Grid& operator=(Grid &&other) noexcept
{
    if (this == &other) {
        return *this;
    }
    // 释放原有数组
    delete[] mytiles;
    // 转移所有权
    _rows_ = other._rows_;
    _cols_ = other._cols_;
    _initialTile_ = other._initialTile_;
    mytiles = other.mytiles;
    // 清空被移动对象
    other.mytiles = nullptr;
    other._rows_ = other._cols_ = 0;
    return *this;
}

// 补充析构函数
~Grid()
{
    delete[] mytiles;
}

另外你原有的拷贝赋值运算符也需要修正内存泄漏问题:

Grid& operator=(const Grid &other)
{
    if (this == &other)
    {
        return *this;
    }
    // 先释放原有内存
    delete[] mytiles;
    _rows_ = other._rows_;
    _cols_ = other._cols_;
    _initialTile_ = other._initialTile_;
    mytiles = new Tile[other._rows_ * other._cols_];
    std::copy(other.mytiles, other.mytiles + other._rows_ * other._cols_, mytiles);
    return *this;
}

问题2:改用std::unique_ptr实现动态数组

你提到的uni_ptr是std::unique_ptr的笔误,针对动态数组需要使用std::unique_ptr的数组特化版本std::unique_ptr<Tile[]>,它会自动调用delete[]释放内存,无需手动管理内存、编写析构函数,且默认生成的移动构造/移动赋值可直接使用,大幅降低出错概率。

替换后的完整Grid类代码如下:

#include <memory>
#include <algorithm>

enum Tile {
    See, Sky, Road
};

class Grid
{
private:
    size_t _rows_ = 0;
    size_t _cols_ = 0;
    Tile _initialTile_;
    // 替换为数组特化的unique_ptr
    std::unique_ptr<Tile[]> mytiles;

public:
    Grid(size_t rows, size_t cols, const Tile &initialTile)
        : _rows_(rows),
          _cols_(cols),
          _initialTile_(initialTile)
    {
        mytiles = std::make_unique<Tile[]>(_cols_ * _rows_);
        std::fill(mytiles.get(), mytiles.get() + _rows_ * _cols_, _initialTile_);
    }

    // 拷贝构造需要手动实现,因为unique_ptr不支持拷贝
    Grid(const Grid &other)
        : _rows_(other._rows_),
          _cols_(other._cols_),
          _initialTile_(other._initialTile_)
    {
        mytiles = std::make_unique<Tile[]>(other._rows_ * other._cols_);
        std::copy(other.mytiles.get(), other.mytiles.get() + other._rows_ * other._cols_, mytiles.get());    
    }

    // 拷贝赋值需要手动实现
    Grid& operator=(const Grid &other)
    {
        if (this == &other)
        {
            return *this;
        }
        _rows_ = other._rows_;
        _cols_ = other._cols_;
        _initialTile_ = other._initialTile_;
        mytiles = std::make_unique<Tile[]>(other._rows_ * other._cols_);
        std::copy(other.mytiles.get(), other.mytiles.get() + other._rows_ * other._cols_, mytiles.get());
        return *this;
    }

    // 移动构造和移动赋值直接用默认生成的即可,unique_ptr原生支持移动语义
    Grid(Grid &&other) noexcept = default;
    Grid& operator=(Grid &&other) noexcept = default;

    // 无需手动写析构函数,unique_ptr会自动释放内存
    ~Grid() = default;
};

替换后访问数组元素的方式和原有裸指针完全一致,直接用mytiles[index]即可,不需要修改其他业务逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 01:15:04