C++中浅拷贝和深拷贝

一、C++中浅拷贝和深拷贝的定义

(1)浅拷贝(Shallow Copy)

仅复制对象的表层数据(如基本数据类型、指针变量本身),不复制指针指向的底层内存。拷贝后,源对象和拷贝对象的指针共享同一块内存。

  • 例如:cv::Mat A = B; 中,AB 共享同一份矩阵数据,修改 A 会影响 B

下图来自:你说的都对【C++】18 浅拷贝和深拷贝

浅拷贝:抄了个 “地址”,东西还是共用的
比如你有一本绝版书(源对象),朋友想要,你没给他买书,只抄了个书架位置(地址)给他。

朋友按地址找到书,要是在书上画了笔记(修改数据),你的书也会有笔记;
要是你把书扔了(源对象释放内存),朋友再按地址找就空了(指针悬空)。

对应代码里的 P0(cv::Rect(0,0,3,3)):
就像你从整本书(P0)里撕了一页(3x3 子矩阵),但这页纸还和原书 “粘” 在一起(共享数据)—— 你改这页的内容,原书里对应的地方也会变,这就是浅拷贝。

(2)深拷贝(Deep Copy)

不仅复制对象的表层数据,还会为指针指向的底层内存分配新空间并复制数据。拷贝后,源对象和拷贝对象的指针指向完全独立的内存,修改其中一个不会影响另一个。

  • 例如:cv::Mat A = B.clone(); 中,A 复制 B 的所有数据,两者完全独立。

下图来自:你说的都对【C++】18 浅拷贝和深拷贝

深拷贝:买了个 “一模一样的新东西”,各自独立
还是那本绝版书,朋友想要,你找出版社复刻了一本完全一样的(新内存 + 复制数据)给他。

朋友在复刻本上画笔记(修改数据),你的原书完全没影响;
你把原书扔了(源对象释放),朋友的复刻本照样能用。

对应代码里的 .clone():
在浅拷贝拿到 3x3 子矩阵后,用 .clone() 相当于把这页纸 “复刻” 了一份,单独交给 cam.K_left—— 后续改 cam.K_left 的数据,和原矩阵 P0 没关系,这就是深拷贝。

一句话总结
浅拷贝:“共享同一套数据”,省时间省空间,但容易互相干扰;
深拷贝:“复制一套独立数据”,费点资源,但安全不冲突。

二、浅拷贝和深拷贝的作用

  • 浅拷贝:快速复制对象,节省内存和时间(无需重新分配内存),适用于临时访问数据且不修改的场景。
  • 深拷贝:保证对象独立性,避免因共享内存导致的意外修改(如源对象释放内存后拷贝对象的指针悬空),适用于需要长期持有数据或修改数据的场景。

三、什么情况下使用?(结合代码示例说明)

//成员函数LoadCalibration加载标定文件,读取并解析 calib 文件
bool KittiDataset::LoadCalibration(const std::string &calib_file, StereoCamera &cam) {
    //打开帧对应的标定文件
    std::ifstream fin(calib_file);
    //检查是否打开成功
    if (!fin.is_open()) {
        std::cerr << "[KittiDataset] Cannot open calib file: " << calib_file << std::endl;
        return false;
    }
    //解析标定文件中灰度相机相关行的标定参数
    std::string line;
    //P0左灰度相机投影矩阵、P1右灰度相机投影矩阵
    cv::Mat P0(3,4,CV_64F), P1(3,4,CV_64F);
    while (std::getline(fin,line)) {
        //找文件中行首是P0
        if (line.rfind("P0:",0) == 0) {
            std::stringstream ss(line.substr(3));
            //3*4=12个数分别填充到P0矩阵中
            //整除结果每 4 个数递增 1(0~3 为 0,4~7 为 1,8~11 为 2)
            //取模结果以 4 为周期循环(0,1,2,3,0,1,2,3,...)
            for (int i=0; i<12; ++i) ss >> P0.at<double>(i/4, i%4);
        }else if (line.rfind("P1:",0) == 0) {
            std::stringstream ss(line.substr(3));
            for (int i=0; i<12; ++i) ss >> P1.at<double>(i/4, i%4);
        }
    }
    fin.close();
    //将参数并赋值到相机结构体中对应参数
    //P=K[R|t],双目相机只有平移无旋转
    //P0=K[I|0]=[K|0] P1=K[I|t]=[K|t]
    cam.K_left = P0(cv::Rect(0,0,3,3)).clone(); //浅拷贝后深拷贝,先靠浅拷贝快速 “揪出” 需要的部分(3x3 子矩阵),再靠深拷贝把这部分变成独立数据存起来,既高效又安全
    //返回加载状态
}
1. 浅拷贝的使用场景:临时访问数据,不修改原数据

代码中 P0(cv::Rect(0,0,3,3)) 是典型的浅拷贝:

  • cv::Rect(0,0,3,3)P0(3x4矩阵)中截取左上角3x3的子矩阵,此时子矩阵与 P0 共享底层数据(浅拷贝)。
  • 这里使用浅拷贝的原因:仅需临时访问 P0 的部分数据(提取内参矩阵 K),无需修改 P0,且子矩阵生命周期短暂(仅用于后续深拷贝),无需独立内存。
2. 深拷贝的使用场景:需要独立持有数据,避免相互影响

代码中 .clone() 实现了深拷贝:

  • cam.K_left 需要长期保存相机内参,且后续可能被单独修改(如相机参数调整)。若直接使用浅拷贝(cam.K_left = P0(cv::Rect(...))),则 cam.K_left 会与 P0 共享数据,一旦 P0 被释放或修改(如函数结束后 P0 销毁),cam.K_left 会变成无效数据(悬空引用)。
  • 因此,通过 .clone() 进行深拷贝,确保 cam.K_left 拥有独立的内存空间,与 P0 完全解耦,保证数据安全性。

总结

  • 浅拷贝适用于临时访问、不修改数据、追求效率的场景(如代码中临时截取子矩阵)。
  • 深拷贝适用于需要长期持有数据、独立修改、保证数据安全的场景(如代码中保存相机内参到结构体)。
    代码中 cv::Rect.clone() 的组合,既利用了浅拷贝的高效性(临时访问),又通过深拷贝保证了数据独立性(长期存储),是两者结合的典型实践。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐