C++ Primer (第五版)-第十三章 拷贝控制

文章目录

  • 概述
  • 13.1拷贝、赋值与销毁
    • 合成拷贝构造函数
    • 拷贝初始化
    • 参数和返回值
    • 拷贝初始化的限制
    • 编译器可以绕过拷贝构造函数
    • 拷贝运算符
    • 析构函数
    • 三/五原则
      • 使用=default
      • 阻止拷贝
      • 合成的拷贝控制成员可能是删除的
    • private拷贝控制
    • 拷贝控制和资源管理
      • 行为像值的类
      • 类值拷贝赋值运算符
      • 定义行为像指针的类
      • 引用计数
      • 定义一个引用计数的类
      • 类指针的拷贝成员“篡改” 引用计数
  • 交换操作
  • 拷贝控制示例
  • 动态内存管理
  • 对象移动
    • 右值引用
    • 移动构造函数和移动赋值运算符
    • 移动迭代器

概述

在这里插入图片描述

13.1拷贝、赋值与销毁

在这里插入图片描述

合成拷贝构造函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

拷贝初始化

在这里插入图片描述
在这里插入图片描述

参数和返回值

在这里插入图片描述

拷贝初始化的限制

在这里插入图片描述

编译器可以绕过拷贝构造函数

在这里插入图片描述

拷贝运算符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

析构函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三/五原则

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

使用=default

在这里插入图片描述

阻止拷贝

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述### 析构函数不能是删除成员

在这里插入图片描述

合成的拷贝控制成员可能是删除的

在这里插入图片描述
在这里插入图片描述

private拷贝控制

在新标准发布之前 ,类是通过将其拷贝构造函数和拷贝赋值运算符芦明为 pr ivate
的来阻止拷贝:

class Priva teCopy {
//元访问说明符 ;接下来的成员默认为p rivate 的;参见 7.2 节 ( 第 240 页 )
//拷贝控制成员是 priv a te 的,因此普通用户代码无法访问
Priva teCopy ( const Priva teCopy& ) ;
PrivateCopy & operator= ( const Priva teCopy& ) ;
//其他成员
public :
Pr ivateCopy ( ) = def au lt ; //使用合成的默认构造函数
~PrivateCopy ( ) ; // 用尸可以定义此类型的对象 ,但无法拷贝它们

由于析构函数是 public 的,用户可以定义 Pr ivateCopy 类型的对象 。但是 ,由于拷贝 构造函数和拷贝赋值运算符是 pr iva te 的,用户代码将不能拷贝这个类型的对象
。但是, 友元和成员函数仍旧可以拷贝对象 。为了阻止友元和成员函数进行拷贝,我们将这些拷贝 控制成员声明为 pr iva t e 的,但并不定义它们 。
声明但不定义 个成员函数是合法的 ( 参见 6. 1.2 节,第 186 页),对此只有一个例外 , 我们将在 15.2.1 节 (第 528 页) 中介绍。试图访问一个未定义的成员将导致
一个链接时错 误。通过声明 (但不定义) pr ivate 的拷贝构造函数 ,我们可以预先阻止任何拷贝该类 型对象的企图 :试图拷贝对象的用户代码将在编译阶段被标记为错 误:成员函数或友元函
数中的拷贝操作将会导致链接时错误 。
在这里插入图片描述

拷贝控制和资源管理

在这里插入图片描述

行为像值的类

在这里插入图片描述
在这里插入图片描述

类值拷贝赋值运算符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

定义行为像指针的类

在这里插入图片描述

引用计数

在这里插入图片描述

定义一个引用计数的类

在这里插入图片描述
在这里插入图片描述

类指针的拷贝成员“篡改” 引用计数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

交换操作

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

拷贝控制示例

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

动态内存管理

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

对象移动

在这里插入图片描述
在这里插入图片描述

右值引用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

移动构造函数和移动赋值运算符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

#pragma once
#include <iostream>
class HasPtr
{friend void swap(HasPtr&, HasPtr&);
public://默认构造函数HasPtr(const std::string& s = std::string()) : ps(new std::string(s)), i(0){}//拷贝构造函数HasPtr(const HasPtr& data) : ps(new std::string(*(data.ps))), i(data.i){}//添加都移动构造函数HasPtr(HasPtr&& P)noexcept :ps(P.ps), i(P.i) {P.ps = nullptr;P.i = 0;}HasPtr& operator=(HasPtr rhs){swap(*this, rhs);return *this;}// 析构函数~HasPtr(){delete ps;}
private:std::string* ps;int i;
};inline void swap(HasPtr& lhs, HasPtr& rhs)
{using std::swap;swap(lhs.ps, rhs.ps); // swap the pointers, not the string dataswap(lhs.i, rhs.i); // swap the int members
}
int main()
{HasPtr data1, data2("123"), data3, data4("abc");data1 = data2;//拷贝语义data3 = std::move(data4);//移动语义
}

所有五个拷贝控制成员应该看作一个整体:一般来说,如果一个类定义了任何一个拷贝操作,它应该定义所有五个操作。如前所述,某些类必须定义拷贝构造函数、拷贝赋值运算符和析构函数。这些类只有一个资源,而拷贝成员必须拷贝此资源。

移动迭代器

#include <iostream>
#include <memory>
#include <string>
#include <utility>
#include <algorithm>
#include <cassert>class StrVec {
public:// 默认构造函数StrVec() : elements(nullptr), first_free(nullptr), cap(nullptr) {std::cout << "Default constructor called." << std::endl;}// 拷贝构造函数StrVec(const StrVec& s) {std::cout << "Copy constructor called." << std::endl;auto newdata = alloc_n_copy(s.begin(), s.end());elements = newdata.first;first_free = cap = newdata.second;}// 移动构造函数StrVec(StrVec&& s) noexcept : elements(s.elements), first_free(s.first_free), cap(s.cap) {std::cout << "Move constructor called." << std::endl;s.elements = s.first_free = s.cap = nullptr;}// 拷贝赋值运算符StrVec& operator=(const StrVec& rhs) {std::cout << "Copy assignment operator called." << std::endl;auto data = alloc_n_copy(rhs.begin(), rhs.end());free();elements = data.first;first_free = cap = data.second;return *this;}// 移动赋值运算符StrVec& operator=(StrVec&& rhs) noexcept {std::cout << "Move assignment operator called." << std::endl;if (this != &rhs) {free();elements = rhs.elements;first_free = rhs.first_free;cap = rhs.cap;rhs.elements = rhs.first_free = rhs.cap = nullptr;}return *this;}// 析构函数~StrVec() {std::cout << "Destructor called." << std::endl;free();}// 拷贝版本的 push_backvoid push_back(const std::string& s) {std::cout << "Copy push_back called with: " << s << std::endl;chk_n_alloc();alloc.construct(first_free++, s);}// 移动版本的 push_backvoid push_back(std::string&& s) {std::cout << "Move push_back called with: " << s << std::endl;chk_n_alloc();alloc.construct(first_free++, std::move(s));}// 返回元素数量size_t size() const { return first_free - elements; }// 返回容量size_t capacity() const { return cap - elements; }// 返回起始迭代器std::string* begin() const { return elements; }// 返回结束迭代器std::string* end() const { return first_free; }// 左值版本的 sorted 方法void sorted() & {std::cout << "Lvalue sorted called." << std::endl;std::sort(begin(), end());}// 右值版本的 sorted 方法StrVec sorted() && {std::cout << "Rvalue sorted called." << std::endl;std::sort(begin(), end());return std::move(*this);}private:std::allocator<std::string> alloc;// 检查是否需要重新分配内存void chk_n_alloc() {if (size() == capacity()) {reallocate();}}// 分配并复制元素std::pair<std::string*, std::string*> alloc_n_copy(const std::string*, const std::string*);// 释放内存void free();// 重新分配内存void reallocate();std::string* elements;std::string* first_free;std::string* cap;
};// 分配并复制元素的实现
std::pair<std::string*, std::string*> StrVec::alloc_n_copy(const std::string* b, const std::string* e) {auto data = alloc.allocate(e - b);return {data, std::uninitialized_copy(b, e, data)};
}// 释放内存的实现
void StrVec::free() {if (elements) {for (auto p = first_free; p != elements; ) {alloc.destroy(--p);}alloc.deallocate(elements, cap - elements);}
}// 重新分配内存的实现
void StrVec::reallocate() {std::cout << "Reallocating memory..." << std::endl;auto newcapacity = size() ? 2 * size() : 1;auto newdata = alloc.allocate(newcapacity);auto dest = newdata;auto elem = elements;for (size_t i = 0; i != size(); ++i) {alloc.construct(dest++, std::move(*elem++));}free();elements = newdata;first_free = dest;cap = elements + newcapacity;
}// 打印 StrVec 中的元素
void printStrVec(const StrVec& vec) {for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;
}// 测试默认构造函数
void testDefaultConstructor() {StrVec vec;assert(vec.size() == 0);std::cout << "Default constructor test passed." << std::endl;
}// 测试拷贝构造函数
void testCopyConstructor() {StrVec vec1;vec1.push_back("apple");vec1.push_back("banana");StrVec vec2(vec1);assert(vec2.size() == vec1.size());auto it1 = vec1.begin();auto it2 = vec2.begin();while (it1 != vec1.end() && it2 != vec2.end()) {assert(*it1 == *it2);++it1;++it2;}std::cout << "Copy constructor test passed." << std::endl;
}// 测试移动构造函数
void testMoveConstructor() {StrVec vec1;vec1.push_back("cherry");vec1.push_back("date");StrVec vec2(std::move(vec1));assert(vec1.size() == 0);assert(vec2.size() == 2);std::cout << "Move constructor test passed." << std::endl;
}// 测试拷贝赋值运算符
void testCopyAssignmentOperator() {StrVec vec1;vec1.push_back("elderberry");vec1.push_back("fig");StrVec vec2;vec2 = vec1;assert(vec2.size() == vec1.size());auto it1 = vec1.begin();auto it2 = vec2.begin();while (it1 != vec1.end() && it2 != vec2.end()) {assert(*it1 == *it2);++it1;++it2;}std::cout << "Copy assignment operator test passed." << std::endl;
}// 测试移动赋值运算符
void testMoveAssignmentOperator() {StrVec vec1;vec1.push_back("grape");vec1.push_back("honeydew");StrVec vec2;vec2 = std::move(vec1);assert(vec1.size() == 0);assert(vec2.size() == 2);std::cout << "Move assignment operator test passed." << std::endl;
}// 测试 push_back 方法
void testPushBack() {StrVec vec;vec.push_back("apple");vec.push_back(std::string("banana"));assert(vec.size() == 2);std::cout << "Push_back test passed." << std::endl;
}// 测试 sorted 方法(左值)
void testSortedLvalue() {StrVec vec;vec.push_back("banana");vec.push_back("apple");vec.push_back("cherry");vec.sorted();auto it = vec.begin();assert(*it == "apple");++it;assert(*it == "banana");++it;assert(*it == "cherry");std::cout << "Sorted (lvalue) test passed." << std::endl;
}// 测试 sorted 方法(右值)
void testSortedRvalue() {StrVec sortedVec = StrVec().push_back("grape").push_back("date").push_back("elderberry").sorted();auto it = sortedVec.begin();assert(*it == "date");++it;assert(*it == "elderberry");++it;assert(*it == "grape");std::cout << "Sorted (rvalue) test passed." << std::endl;
}int main() {testDefaultConstructor();testCopyConstructor();testMoveConstructor();testCopyAssignmentOperator();testMoveAssignmentOperator();testPushBack();testSortedLvalue();testSortedRvalue();std::cout << "All tests passed!" << std::endl;return 0;
}    
}    

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/75927.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Vue el-from的el-form-item v-for循环表单如何校验rules(一)

实际业务需求场景&#xff1a; 新增或编辑页面&#xff08;基础信息表单&#xff0c;一个数据列表的表单&#xff09;&#xff0c;数据列表里面的表单数是动态添加的。数据可新增、可删除&#xff0c;在表单保存前&#xff0c;常常需要做表单必填项的校验&#xff0c;校验通过以…

测试100问:http和https的区别是什么?

哈喽&#xff0c;大家好&#xff0c;我是十二&#xff0c;今天给大家分享的问题是&#xff1a;http和https的区别是什么&#xff1f; 首先我们要知道 HTTP 协议传播的数据都是未加密的&#xff0c;也就是明文的&#xff0c;因此呢使用 http协议传输一些隐私信息也就非常不安全&…

YOLOv3超详细解读(三):源码解析:数据处理模块

一、概述 YOLOv3&#xff08;You Only Look Once v3&#xff09;是一种高效的目标检测算法&#xff0c;其数据处理模块是训练和推理流程的核心部分。本文将深入分析Ultralytics团队基于PyTorch实现的YOLOv3源码中的数据处理模块&#xff0c;重点探讨数据加载、预处理和数据增强…

每日算法(双指针算法)(Day 1)

双指针算法 1.算法题目&#xff08;移动零&#xff09;2.讲解算法原理3.编写代码 1.算法题目&#xff08;移动零&#xff09; 2.讲解算法原理 数组划分&#xff0c;数组分块&#xff08;快排里面最核心的一步&#xff09;只需把0改为tmp 双指针算法&#xff1a;利用数组下标来…

2025蓝桥杯python A组省赛 题解

真捐款去了&#xff0c;好长时间没练了&#xff0c;感觉脑子和手都不转悠了。 B F BF BF 赛时都写假了&#xff0c; G G G 也只写了爆搜。 题解其实队友都写好了&#xff0c;我就粘一下自己的代码&#xff0c;稍微提点个人的理解水一篇题解 队友题解 2025蓝桥杯C A组省赛 题…

测试基础笔记第四天(html)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 html介绍1. 介绍2.骨架标签3.常用标签标题标签段落标签超链接标签图片标签换行和空格标签布局标签input标签&#xff08;变形金刚&#xff09;form标签列表标签 htm…

10 穴 汽车连接器的15个设计特点

汽车行业严重依赖卓越的电气系统来确保功能和可靠性。这些系统的关键组件是 10 腔连接器&#xff0c;它为布线和信号传输提供解决方案。制造商和工程师必须仔细评估这些连接器的设计特性&#xff0c;以优化性能和安全性。 本博客研究了汽车 10 腔连接器的 15 个设计特征&#…

Summary

一、数据结构 1.1 哈希 主要是HashMap和HashSet&#xff1b;其中HashSet底层是一个HashMap属性。 // 获取HashMap元素,HashSet均不支持 map.keySet (); // Set<k> map.values (; // Collection<V> map.entrySet();//Set<Map.Entry<K,V>> for (Map.E…

【Leetcode-Hot100】最小覆盖子串

题目 解答 想到使用双指针哈希表来实现&#xff0c;双指针的left和right控制实现可满足字符串。 class Solution(object):def minWindow(self, s, t):""":type s: str:type t: str:rtype: str"""len_s, len_t len(s), len(t)hash_map {}for…

Flutter 播放利器:`media_kit` 的详细介绍与使用指南

在 Flutter 项目中实现音视频播放&#xff0c;开发者过去主要依赖如 video_player、just_audio 等第三方库&#xff0c;但这些库或多或少存在一些局限性&#xff0c;比如平台兼容性差、定制能力不足、播放格式有限等问题。 而 media_kit 是近年崛起的一款全平台音视频播放解决…

4.14【Q】pc homework3

我正在学习并行计算&#xff0c;解决这个问题&#xff1f;详细解释&#xff0c;越细节越好 我正在学习并行计算&#xff0c;“首次允许在 taskloop 构造中使用 reduction 子句&#xff0c;并引入了 task_reduction&#xff08;用于 taskgroup 构造&#xff09;和 in_reduction&…

ArrayList vs LinkedList,HashMap vs TreeMap:如何选择最适合的集合类?

精心整理了最新的面试资料和简历模板&#xff0c;有需要的可以自行获取 点击前往百度网盘获取 点击前往夸克网盘获取 在 Java 开发中&#xff0c;集合类的选择直接影响程序的性能和代码的可维护性。不同的数据结构适用于不同的场景&#xff0c;盲目使用可能导致内存浪费、性能…

大模型训练显存压缩实战:ZeRO-3 vs 梯度累积 vs 量化混合策略

一、显存瓶颈的本质与挑战 大模型训练面临的核心矛盾是模型参数量指数级增长与GPU显存容量线性提升之间的鸿沟。以175B参数模型为例&#xff0c;其显存消耗主要来自三个方面&#xff1a; 参数存储‌&#xff1a;FP32精度下需700GB显存‌梯度缓存‌&#xff1a;反向传播产生的…

边缘计算与隐私计算的融合:构建数据经济的“隐形护盾“

在数据成为核心生产要素的今天&#xff0c;边缘计算与隐私计算的交汇正在重塑技术生态。这并非简单的技术叠加&#xff0c;而是一场关于数据主权、算力分配与信任机制的深度博弈。本文将从"数据流动的拓扑学"视角&#xff0c;探讨二者融合如何重构数字社会的基础设施…

Obsidian 文件夹体系构建 -INKA

Obsidian 文件夹体系构建 -INKA 本篇文章主要分享一下自己折腾学习实践过的 INKA 框架方法。原地址&#xff1a;Obsidian文件夹体系构建–INKA。 文章目录 Obsidian 文件夹体系构建 -INKA前言INKA简介INKA 理论最佳实践实际应用 反思 前言 上文 Obsidian文件夹体系构建-ACCES…

ocr-不动产权识别

目录 一、在阿里云申请ocr识别服务 二、创建springboot项目 三、后续 一、在阿里云申请ocr识别服务 在线体验&#xff1a;房产证图片上传 [阿里官方]不动产权证OCR文字识别_API专区_云市场-阿里云 (aliyun.com) 可以选择一毛500次这个 当然也可以白嫖100 下面有个在线调试…

LeetCode算法题(Go语言实现)_47

题目 给你一个 m x n 的迷宫矩阵 maze &#xff08;下标从 0 开始&#xff09;&#xff0c;矩阵中有空格子&#xff08;用 ‘.’ 表示&#xff09;和墙&#xff08;用 ‘’ 表示&#xff09;。同时给你迷宫的入口 entrance &#xff0c;用 entrance [entrancerow, entrancecol…

The Strict Teacher (Hard Version) 去除无效的干扰!巧妙转化

文章目录 The Strict Teacher (Hard Version) 思考问题&#xff01;那么多个人抓一个人&#xff0c;是否是每一个人都是对于最优策略的答案是有贡献的&#xff1f;答案是否定的&#xff0c;其实问题可以简化为三种情况&#xff1a; 所有的老师都在大卫的右边&#xff0c;…

《 Reinforcement Learning for Education: Opportunities and Challenges》全文阅读

Reinforcement Learning for Education: Opportunities and Challenges 面向教育的强化学习&#xff1a;机遇与挑战 摘要 本综述文章源自作者在 Educational Data Mining (EDM) 2021 会议期间组织的 RL4ED 研讨会。我们组织了这一研讨会&#xff0c;作为一项社区建设工作的组…

idea的快捷键使用以及相关设置

文章目录 快捷键常用设置 快捷键 快捷键作用ctrlshift/注释选中内容Ctrl /注释一行/** Enter文档注释ALT SHIFT ↑, ALT SHIFT ↓上下移动当前代码Ctrl ALT L格式化代码Ctrl X删除所在行并复制该行Ctrl D复制当前行数据到下一行main/psvm快速生成入口程序soutSystem.o…