最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C++ move 的作用詳解及陷阱最佳實(shí)踐

 更新時(shí)間:2025年12月05日 11:49:08   作者:愛(ài)學(xué)習(xí)的大牛123  
文章詳細(xì)介紹了C++中的`std::move`函數(shù)的作用,包括為什么需要它、它的本質(zhì)、典型使用場(chǎng)景、以及一些常見(jiàn)陷阱和最佳實(shí)踐,感興趣的朋友跟隨小編一起看看吧

C++ move 的作用詳解

這是個(gè)核心概念題!讓我從淺到深給你講清楚。

一、一句話總結(jié)

std::move 的作用:將對(duì)象轉(zhuǎn)換為右值引用,允許資源被"移動(dòng)"而非"拷貝",避免昂貴的深拷貝操作。

二、為什么需要 move?

??C++98/03 的痛點(diǎn)

// C++11 之前
vector<string> create_large_vector() {
    vector<string> result(1000000, "hello");
    return result;  // ?? 拷貝 100萬(wàn)個(gè) string!
}
vector<string> v = create_large_vector();
// 內(nèi)部發(fā)生:
// 1. 分配新內(nèi)存
// 2. 拷貝 100萬(wàn)個(gè) string(每個(gè)又要拷貝字符串內(nèi)容)
// 3. 銷(xiāo)毀臨時(shí)對(duì)象
// 性能災(zāi)難!

?C++11 的解決方案:移動(dòng)語(yǔ)義

// C++11
vector<string> create_large_vector() {
    vector<string> result(1000000, "hello");
    return result;  // ? 移動(dòng),幾乎零開(kāi)銷(xiāo)!
}
vector<string> v = create_large_vector();
// 內(nèi)部發(fā)生:
// 1. 交換指針(僅復(fù)制幾個(gè)字節(jié))
// 2. 臨時(shí)對(duì)象被置空
// 快如閃電!

三、move 的本質(zhì)

??move 不移動(dòng)任何東西!

// std::move 的實(shí)際實(shí)現(xiàn)(簡(jiǎn)化版)
template<typename T>
typename remove_reference<T>::type&& move(T&& t) noexcept {
    return static_cast<typename remove_reference<T>::type&&>(t);
}
// 它只是一個(gè)類(lèi)型轉(zhuǎn)換!
// 左值 → 右值引用

核心理解

  • ? std::move無(wú)條件的類(lèi)型轉(zhuǎn)換
  • ? 它把左值轉(zhuǎn)換成右值引用
  • ? 真正的"移動(dòng)"發(fā)生在移動(dòng)構(gòu)造函數(shù)移動(dòng)賦值運(yùn)算符

四、拷貝 vs 移動(dòng)對(duì)比

??深拷貝(C++98)

class String {
    char* data;
    size_t size;
public:
    // 拷貝構(gòu)造函數(shù)
    String(const String& other) {
        size = other.size;
        data = new char[size];           // 1. 分配新內(nèi)存
        memcpy(data, other.data, size);  // 2. 拷貝數(shù)據(jù)
        // ?? 慢!
    }
    // 拷貝賦值運(yùn)算符
    String& operator=(const String& other) {
        if (this != &other) {
            delete[] data;               // 1. 釋放舊內(nèi)存
            size = other.size;
            data = new char[size];       // 2. 分配新內(nèi)存
            memcpy(data, other.data, size);  // 3. 拷貝數(shù)據(jù)
        }
        return *this;
    }
};
String s1("hello");
String s2 = s1;  // 深拷貝:分配內(nèi)存 + 拷貝 5 字節(jié)

?移動(dòng)(C++11)

class String {
    char* data;
    size_t size;
public:
    // 移動(dòng)構(gòu)造函數(shù)
    String(String&& other) noexcept {
        data = other.data;        // 1. 偷走指針
        size = other.size;
        other.data = nullptr;     // 2. 置空源對(duì)象
        other.size = 0;
        // ? 快!只復(fù)制指針
    }
    // 移動(dòng)賦值運(yùn)算符
    String& operator=(String&& other) noexcept {
        if (this != &other) {
            delete[] data;        // 1. 釋放舊內(nèi)存
            data = other.data;    // 2. 偷走指針
            size = other.size;
            other.data = nullptr; // 3. 置空源對(duì)象
            other.size = 0;
        }
        return *this;
    }
};
String s1("hello");
String s2 = std::move(s1);  // 移動(dòng):只復(fù)制指針,8 字節(jié)
// s1 現(xiàn)在是空的(被掏空)

??性能對(duì)比

// 移動(dòng) 100萬(wàn)個(gè) string
vector<string> v1, v2;
for (int i = 0; i < 1000000; ++i) {
    v1.push_back(string(1000, 'a'));  // 每個(gè) 1KB
}
// 拷貝
auto start = now();
v2 = v1;  // 深拷貝:1GB 數(shù)據(jù)
auto end = now();
// 耗時(shí):~500ms
// 移動(dòng)
auto start = now();
v2 = std::move(v1);  // 移動(dòng):只復(fù)制幾個(gè)指針
auto end = now();
// 耗時(shí):~1ms ? 快 500 倍!

五、move 的典型使用場(chǎng)景

?場(chǎng)景 1:函數(shù)返回大對(duì)象

// 返回局部變量
vector<int> createVector() {
    vector<int> result(1000000);
    // ...
    return result;  // C++11 自動(dòng)移動(dòng)(NRVO優(yōu)化)
}
// 顯式 move(通常不需要)
vector<int> createVector() {
    vector<int> result(1000000);
    return std::move(result);  // ?? 不推薦,會(huì)阻止 RVO
}

?場(chǎng)景 2:容器插入臨時(shí)對(duì)象

vector<string> names;
// C++98:拷貝
string temp = "Alice";
names.push_back(temp);  // 拷貝 temp
// C++11:移動(dòng)
string temp = "Alice";
names.push_back(std::move(temp));  // 移動(dòng) temp
// temp 現(xiàn)在是空的
// 更好:直接構(gòu)造
names.emplace_back("Alice");  // 最優(yōu)

?場(chǎng)景 3:交換對(duì)象

// C++98:三次拷貝
void swap(string& a, string& b) {
    string temp = a;  // 拷貝
    a = b;            // 拷貝
    b = temp;         // 拷貝
}
// C++11:三次移動(dòng)
void swap(string& a, string& b) {
    string temp = std::move(a);  // 移動(dòng)
    a = std::move(b);             // 移動(dòng)
    b = std::move(temp);          // 移動(dòng)
}
// 標(biāo)準(zhǔn)庫(kù) std::swap 就是這樣實(shí)現(xiàn)的

?場(chǎng)景 4:unique_ptr 轉(zhuǎn)移所有權(quán)

unique_ptr<int> p1 = make_unique<int>(42);
unique_ptr<int> p2 = p1;              // ? 編譯錯(cuò)誤:禁止拷貝
unique_ptr<int> p2 = std::move(p1);   // ? 移動(dòng):轉(zhuǎn)移所有權(quán)
// 現(xiàn)在 p1 是空的,p2 擁有對(duì)象
cout << (p1 == nullptr);  // true
cout << *p2;              // 42

?場(chǎng)景 5:容器元素轉(zhuǎn)移

vector<string> v1 = {"apple", "banana", "cherry"};
vector<string> v2;
// 移動(dòng)單個(gè)元素
v2.push_back(std::move(v1[0]));  // v1[0] 變成空字符串
// 移動(dòng)整個(gè)容器
v2 = std::move(v1);  // v1 變成空容器

?場(chǎng)景 6:多線程傳遞數(shù)據(jù)

void process(vector<int> data) {
    // 處理數(shù)據(jù)
}
vector<int> large_data(1000000);
// 傳遞給線程(移動(dòng),避免拷貝)
thread t(process, std::move(large_data));
// large_data 現(xiàn)在是空的,數(shù)據(jù)已轉(zhuǎn)移到線程

?場(chǎng)景 7:成員變量初始化

class Widget {
    string name;
    vector<int> data;
public:
    // 移動(dòng)參數(shù)到成員變量
    Widget(string n, vector<int> d) 
        : name(std::move(n))      // 移動(dòng)
        , data(std::move(d)) {    // 移動(dòng)
    }
};
string s = "widget";
vector<int> v = {1, 2, 3};
Widget w(std::move(s), std::move(v));  // s 和 v 被掏空

六、move 后的對(duì)象狀態(tài)

??關(guān)鍵規(guī)則:移后源對(duì)象處于"有效但未指定"狀態(tài)

string s1 = "hello";
string s2 = std::move(s1);
// s1 的狀態(tài):
// ? 有效:可以安全地調(diào)用成員函數(shù)
// ?? 未指定:不知道具體內(nèi)容
// 安全操作
s1.clear();           // ? 可以
s1 = "new value";     // ? 可以
if (s1.empty()) {}    // ? 可以
s1.~string();         // ? 析構(gòu)函數(shù)總是被調(diào)用
// 不安全操作
cout << s1;           // ?? 可能輸出空字符串或其他
cout << s1[0];        // ? 未定義行為(如果 s1 為空)

??STL 容器移動(dòng)后的保證

vector<int> v1 = {1, 2, 3};
vector<int> v2 = std::move(v1);
// v1 的狀態(tài):
// ? 保證為空容器
cout << v1.size();     // 0
cout << v1.empty();    // true
v1.push_back(42);      // ? 可以繼續(xù)使用

七、常見(jiàn)陷阱

?陷阱 1:對(duì)右值使用 move

vector<int> v = std::move(createVector());
//              ^^^^^^^^^ 多余!createVector() 已經(jīng)是右值
// 正確寫(xiě)法
vector<int> v = createVector();  // 自動(dòng)移動(dòng)

?陷阱 2:move 后繼續(xù)使用

string s1 = "hello";
string s2 = std::move(s1);
cout << s1.size();  // ?? 結(jié)果未定義(可能是 0,也可能不是)
// 正確寫(xiě)法
string s1 = "hello";
string s2 = std::move(s1);
s1.clear();         // 先重置
s1 = "new value";   // 再使用

?陷阱 3:const 對(duì)象無(wú)法移動(dòng)

const string s1 = "hello";
string s2 = std::move(s1);  // ?? 仍然是拷貝!
// 原因:
// 移動(dòng)構(gòu)造函數(shù)簽名:String(String&& other)
// const 左值轉(zhuǎn)換后:const String&&
// 無(wú)法匹配,退化為拷貝構(gòu)造函數(shù)

?陷阱 4:返回局部變量時(shí)使用 move(阻止 RVO)

// ? 錯(cuò)誤
string create() {
    string s = "hello";
    return std::move(s);  // 阻止 NRVO 優(yōu)化
}
// ? 正確
string create() {
    string s = "hello";
    return s;  // 編譯器自動(dòng)優(yōu)化(RVO/NRVO)
}

八、何時(shí)必須用 move?

// 1. 轉(zhuǎn)移 unique_ptr 所有權(quán)
unique_ptr<int> p1 = make_unique<int>(42);
unique_ptr<int> p2 = std::move(p1);  // 必須
// 2. 將左值傳給只接受右值的函數(shù)
void process(vector<int>&& v);  // 只接受右值
vector<int> data = {1, 2, 3};
process(std::move(data));  // 必須
// 3. 容器中移動(dòng)元素
vector<string> v1 = {"a", "b"};
vector<string> v2;
v2.push_back(std::move(v1[0]));  // 需要
// 4. 實(shí)現(xiàn)移動(dòng)語(yǔ)義
class MyClass {
    MyClass(MyClass&& other) noexcept {
        data = std::move(other.data);  // 遞歸移動(dòng)成員
    }
};

九、性能數(shù)據(jù)

struct LargeObject {
    vector<int> data;
    LargeObject() : data(1000000) {}
};
// 測(cè)試拷貝 vs 移動(dòng)(1000 次)
auto test_copy = [&]() {
    vector<LargeObject> v;
    for (int i = 0; i < 1000; ++i) {
        LargeObject obj;
        v.push_back(obj);  // 拷貝
    }
};
auto test_move = [&]() {
    vector<LargeObject> v;
    for (int i = 0; i < 1000; ++i) {
        LargeObject obj;
        v.push_back(std::move(obj));  // 移動(dòng)
    }
};
// 結(jié)果(典型值)
拷貝:5000ms  (分配+拷貝 4GB 數(shù)據(jù))
移動(dòng):50ms    (只拷貝指針)
? 快 100 倍!

十、最佳實(shí)踐

?規(guī)則總結(jié)

// 1. 返回局部變量:不要 move
return result;  // 讓編譯器優(yōu)化
// 2. 轉(zhuǎn)移容器/智能指針:必須 move
v2 = std::move(v1);
p2 = std::move(p1);
// 3. 傳參給右值引用函數(shù):使用 move
void func(string&& s);
func(std::move(my_string));
// 4. 移動(dòng)成員變量:使用 move
Widget(string s) : name(std::move(s)) {}
// 5. 優(yōu)先 emplace_back 而非 push_back + move
v.emplace_back(args...);  // 最優(yōu)

??記憶口訣

move 不移動(dòng),只轉(zhuǎn)換
左值變右值,資源可轉(zhuǎn)移
拷貝變移動(dòng),性能翻百倍
移后可析構(gòu),內(nèi)容不保證

十一、與其他特性的關(guān)系

// move + perfect forwarding
template<typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg));  // 完美轉(zhuǎn)發(fā)
}
// move + RVO
string create() {
    return string("hello");  // RVO,無(wú)需 move
}
// move + emplace
v.emplace_back(std::move(s));  // 組合使用

總結(jié)

方面核心要點(diǎn)
本質(zhì)類(lèi)型轉(zhuǎn)換:左值 → 右值引用
目的避免深拷貝,實(shí)現(xiàn)資源轉(zhuǎn)移
代價(jià)幾乎零開(kāi)銷(xiāo)(只復(fù)制指針)
副作用源對(duì)象被"掏空"
適用大對(duì)象、容器、智能指針
性能提升10-1000 倍(取決于對(duì)象大?。?/td>

一句話:std::move 讓 C++ 從"拷貝語(yǔ)義"進(jìn)化到"移動(dòng)語(yǔ)義",是現(xiàn)代 C++ 性能優(yōu)化的基石。

有具體的使用場(chǎng)景嗎?我可以幫你分析要不要用 move!

到此這篇關(guān)于C++ move 的作用詳解及陷阱最佳實(shí)踐的文章就介紹到這了,更多相關(guān)C++ move 使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 指針操作數(shù)組的兩種方法(總結(jié))

    指針操作數(shù)組的兩種方法(總結(jié))

    下面小編就為大家?guī)?lái)一篇指針操作數(shù)組的兩種方法(總結(jié))。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-05-05
  • C++中可以接受任意多個(gè)參數(shù)的函數(shù)定義方法(詳解)

    C++中可以接受任意多個(gè)參數(shù)的函數(shù)定義方法(詳解)

    下面小編就為大家?guī)?lái)一篇C++中可以接受任意多個(gè)參數(shù)的函數(shù)定義方法(詳解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10
  • C++ 中類(lèi)對(duì)象類(lèi)型的轉(zhuǎn)化的實(shí)例詳解

    C++ 中類(lèi)對(duì)象類(lèi)型的轉(zhuǎn)化的實(shí)例詳解

    這篇文章主要介紹了C++ 中類(lèi)對(duì)象類(lèi)型的轉(zhuǎn)化的實(shí)例詳解的相關(guān)資料,這里提供實(shí)例幫助大家學(xué)習(xí)理解這部分內(nèi)容,需要的朋友可以參考下
    2017-08-08
  • C/C++實(shí)現(xiàn)推箱子小游戲

    C/C++實(shí)現(xiàn)推箱子小游戲

    這篇文章主要為大家詳細(xì)介紹了C/C++實(shí)現(xiàn)推箱子小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • 一文帶你吃透C++繼承

    一文帶你吃透C++繼承

    繼承是C++語(yǔ)言的一個(gè)重要特性,繼承使得軟件(代碼)復(fù)用變得簡(jiǎn)單、易行,可以通過(guò)繼承復(fù)用已有的程序資源,縮短軟件開(kāi)發(fā)的周期,本就帶大家吃透C++繼承,需要的朋友可以參考下
    2023-06-06
  • C語(yǔ)言與C++中關(guān)于字符串使用的比較

    C語(yǔ)言與C++中關(guān)于字符串使用的比較

    字符串是我們?cè)偈煜げ贿^(guò)的東西了,任何語(yǔ)言中字符串都是基礎(chǔ)都要經(jīng)常用到,那么在不同語(yǔ)言中字符串的用法一樣嗎?下面我們來(lái)看看C語(yǔ)言與C++中字符串使用的比較
    2022-05-05
  • 詳解C語(yǔ)言和Python中的線程混用

    詳解C語(yǔ)言和Python中的線程混用

    這篇文章主要介紹了C和Python中的線程混用的相關(guān)資料,文中講解非常細(xì)致,幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • C++記錄程序運(yùn)行時(shí)間的四種方法

    C++記錄程序運(yùn)行時(shí)間的四種方法

    在學(xué)習(xí)過(guò)程中很重要的一個(gè)必會(huì)的小技巧:計(jì)算某一段代碼的執(zhí)行時(shí)間,可以用來(lái)分析代碼的效率和算法的時(shí)間復(fù)雜度等等(個(gè)人主要是在總結(jié)各種排序算法時(shí)遇到的這個(gè)方法),本文給大家介紹了C++記錄程序運(yùn)行時(shí)間的四種方法,需要的朋友可以參考下
    2025-03-03
  • C語(yǔ)言判斷數(shù)是否為素?cái)?shù)與素?cái)?shù)輸出

    C語(yǔ)言判斷數(shù)是否為素?cái)?shù)與素?cái)?shù)輸出

    大家好,本篇文章主要講的是C語(yǔ)言判斷數(shù)是否為素?cái)?shù)與素?cái)?shù)輸出,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話記得收藏一下,方便下次瀏覽
    2021-12-12
  • 一文搞懂C++中的四種強(qiáng)制類(lèi)型轉(zhuǎn)換

    一文搞懂C++中的四種強(qiáng)制類(lèi)型轉(zhuǎn)換

    很多朋友向小編了解C語(yǔ)言中怎么進(jìn)行強(qiáng)制類(lèi)型轉(zhuǎn)換呢?在這小編告訴大家強(qiáng)制類(lèi)型轉(zhuǎn)換可以分為兩種,一種是隱式類(lèi)型轉(zhuǎn)換一種是顯示類(lèi)型轉(zhuǎn)換,下面通過(guò)示例代碼給大家介紹下,需要的朋友參考下吧
    2021-07-07

最新評(píng)論

南漳县| 都兰县| 井冈山市| 南投县| 逊克县| 郎溪县| 平陆县| 紫金县| 涡阳县| 封丘县| 鹤壁市| 武乡县| 玛多县| 德州市| 繁峙县| 娄烦县| 松江区| 黔南| 策勒县| 岗巴县| 旺苍县| 罗田县| 商都县| 上林县| 偏关县| 铁岭县| 元氏县| 乌兰县| 马龙县| 永济市| 辽宁省| 肇庆市| 达州市| 石嘴山市| 互助| 织金县| 临朐县| 蒙山县| 黔西县| 团风县| 深州市|