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.pswp.cn/web/75927.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/75927.shtml
英文地址,請注明出處:http://en.pswp.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…