偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

當(dāng)我把 push_back 換成 emplace_back 后,代碼性能竟然......

開發(fā)
如果你經(jīng)常和 C++ 的 vector、list 這些容器打交道,那么今天這篇文章絕對值得你花幾分鐘時(shí)間——因?yàn)槲乙嬖V你一個(gè)小技巧,它能讓你的代碼不僅寫起來更爽,還能跑得更快!

大家好,我是小康。

你有沒有過這樣的經(jīng)歷?寫了一大堆代碼,明明邏輯沒問題,程序跑得卻像蝸牛一樣慢。特別是當(dāng)你在處理大量數(shù)據(jù),往容器里瘋狂塞東西的時(shí)候。

如果你經(jīng)常和 C++ 的 vector、list 這些容器打交道,那么今天這篇文章絕對值得你花幾分鐘時(shí)間——因?yàn)槲乙嬖V你一個(gè)小技巧,它能讓你的代碼不僅寫起來更爽,還能跑得更快!

它就是容器的"隱藏技能":emplace_back()。

"又是一個(gè)新函數(shù)?我的push_back不香了嗎?"

別急,咱們先來看個(gè)例子,感受一下這兩者的區(qū)別:

#include <vector>
#include <string>

class Person {
public:
    Person(std::string name, int age) : m_name(name), m_age(age) {
        printf("構(gòu)造了一個(gè)人:%s, %d歲\n", name.c_str(), age);
    }
    
    // 拷貝構(gòu)造函數(shù)
    Person(const Person& other) : m_name(other.m_name), m_age(other.m_age) {
        printf("拷貝構(gòu)造了一個(gè)人:%s\n", m_name.c_str());
    }
    
private:
    std::string m_name;
    int m_age;
};

int main() {
    std::vector<Person> people;
    
    printf("=== 使用push_back ===\n");
    people.push_back(Person("張三", 25));
    
    people.clear();  // 清空容器
    
    printf("\n=== 使用emplace_back ===\n");
    people.emplace_back("李四", 30);
}

運(yùn)行這段代碼,你會看到這樣的輸出:

=== 使用push_back ===
構(gòu)造了一個(gè)人:張三, 25歲
拷貝構(gòu)造了一個(gè)人:張三

=== 使用emplace_back ===
構(gòu)造了一個(gè)人:李四, 30歲

看出區(qū)別了嗎?

  • 使用push_back時(shí),我們先創(chuàng)建了一個(gè)臨時(shí)的 Person 對象,然后 vector 把它拷貝到容器里
  • 而使用emplace_back時(shí),我們直接傳入構(gòu)造 Person 所需的參數(shù),vector 直接在容器內(nèi)部構(gòu)造對象

結(jié)果就是:push_back額外調(diào)用了一次拷貝構(gòu)造函數(shù),而emplace_back沒有!

"所以emplace_back就是直接傳構(gòu)造函數(shù)參數(shù)?"

沒錯(cuò)!這就是它最大的特點(diǎn)。

  • push_back(x) 需要你先構(gòu)造好一個(gè)對象x,然后把它放進(jìn)容器
  • emplace_back(args...) 則是直接把構(gòu)造函數(shù)的參數(shù) args 傳進(jìn)去,在容器內(nèi)部構(gòu)造對象

這個(gè)差別看似小,實(shí)際上在性能上卻能帶來很大的提升,尤其是當(dāng):

對象構(gòu)造成本高(比如有很多成員變量)

拷貝成本高(比如內(nèi)部有動態(tài)分配的內(nèi)存)

你需要插入大量對象時(shí)

"來點(diǎn)實(shí)際的例子!"

好的,我們來看一個(gè)真正能展示差異的例子。我們創(chuàng)建一個(gè)拷貝成本真正很高的類,這樣才能看出 emplace_back 的威力:

#include <vector>
#include <string>
#include <chrono>
#include <iostream>
#include <memory>

// 設(shè)計(jì)一個(gè)拷貝成本很高的類
class ExpensiveToCopy {
public:
    // 構(gòu)造函數(shù) - 創(chuàng)建一個(gè)大數(shù)組
    ExpensiveToCopy(const std::string& name, int dataSize) 
        : m_name(name), m_dataSize(dataSize) {
        // 分配大量內(nèi)存,模擬昂貴的資源
        m_data = new int[dataSize];
        for (int i = 0; i < dataSize; i++) {
            m_data[i] = i;  // 初始化數(shù)據(jù)
        }
    }
    
    // 拷貝構(gòu)造函數(shù) - 非常昂貴,需要復(fù)制整個(gè)大數(shù)組
    ExpensiveToCopy(const ExpensiveToCopy& other)
        : m_name(other.m_name), m_dataSize(other.m_dataSize) {
        // 深拷貝,非常耗時(shí)
        m_data = new int[m_dataSize];
        for (int i = 0; i < m_dataSize; i++) {
            m_data[i] = other.m_data[i];
        }
        
        // 輸出提示以便觀察拷貝構(gòu)造函數(shù)的調(diào)用情況
        std::cout << "拷貝構(gòu)造: " << m_name << std::endl;
    }
    
    // 析構(gòu)函數(shù)
    ~ExpensiveToCopy() {
        delete[] m_data;
    }
    
    // 禁用賦值運(yùn)算符以簡化例子
    ExpensiveToCopy& operator=(const ExpensiveToCopy&) = delete;
    
private:
    std::string m_name;
    int* m_data;
    int m_dataSize;
};

// 計(jì)時(shí)輔助函數(shù)
template<typename Func>
long long timeIt(Func func) {
    auto start = std::chrono::high_resolution_clock::now();
    func();
    auto end = std::chrono::high_resolution_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
}

int main() {
    const int COUNT = 100;  // 對象數(shù)量,減少一點(diǎn)以便看到輸出
    const int DATA_SIZE = 100000;  // 每個(gè)對象中數(shù)組的大小
    
    std::cout << "=== 測試push_back ===\n";
    long long pushTime = timeIt([&]() {
        std::vector<ExpensiveToCopy> objects;
        objects.reserve(COUNT);  // 預(yù)分配空間避免重新分配的影響
        
        for (int i = 0; i < COUNT; i++) {
            // 創(chuàng)建臨時(shí)對象然后放入vector
            // 這個(gè)過程會調(diào)用拷貝構(gòu)造函數(shù)
            objects.push_back(ExpensiveToCopy("對象" + std::to_string(i), DATA_SIZE));
        }
    });
    
    std::cout << "\n=== 測試emplace_back ===\n";
    long long emplaceTime = timeIt([&]() {
        std::vector<ExpensiveToCopy> objects;
        objects.reserve(COUNT);  // 預(yù)分配空間避免重新分配的影響
        
        for (int i = 0; i < COUNT; i++) {
            // 直接傳遞構(gòu)造函數(shù)參數(shù)
            // 直接在vector內(nèi)部構(gòu)造對象,避免了拷貝
            objects.emplace_back("對象" + std::to_string(i), DATA_SIZE);
        }
    });
    
    std::cout << "\npush_back耗時(shí): " << pushTime << " 微秒" << std::endl;
    std::cout << "emplace_back耗時(shí): " << emplaceTime << " 微秒" << std::endl;
    double percentDiff = (static_cast<double>(pushTime) / emplaceTime - 1.0) * 100.0;
    std::cout << "性能差異: push_back比emplace_back慢了 " << percentDiff << "%" << std::endl;
}

在我的電腦上,大約是這樣的結(jié)果:

=== 測試emplace_back ===

push_back耗時(shí): 66979 微秒
emplace_back耗時(shí): 35858 微秒
性能差異: push_back比emplace_back慢了 86.7896%

這意味著push_back比emplace_back慢了約86%!這可不是小數(shù)目,尤其是在處理大對象時(shí)。

"看起來emplace_back完勝啊!為什么還有人用push_back?"

好問題!emplace_back雖然在大多數(shù)情況下更快,但并不是所有場景都適合用它:

  • 當(dāng)你已經(jīng)有一個(gè)現(xiàn)成的對象時(shí),push_back可能更直觀
  • 對于基本類型(int, double等),兩者性能差異可以忽略不計(jì)
  • 對于某些編譯器優(yōu)化情況,比如移動語義,差距可能不明顯

來看一個(gè)例子,說明什么時(shí)候兩者其實(shí)差不多:

std::vector<int> numbers;

// 對于基本類型,這兩個(gè)是等價(jià)的
numbers.push_back(42);
numbers.emplace_back(42);

// 如果已經(jīng)有一個(gè)現(xiàn)成的對象
std::string name = "張三";
std::vector<std::string> names;

// 這種情況下,如果 string 支持移動構(gòu)造,兩者性能接近
names.push_back(name);               // 拷貝name
names.push_back(std::move(name));    // 移動name(推薦)
names.emplace_back(name);            // 拷貝name
names.emplace_back(std::move(name)); // 移動name(推薦)

"完美轉(zhuǎn)發(fā)是什么鬼?聽說emplace_back跟這個(gè)有關(guān)?"

沒錯(cuò)!emplace_back的強(qiáng)大之處,部分來自于它使用了"完美轉(zhuǎn)發(fā)"(Perfect Forwarding)技術(shù)。

簡單來說,完美轉(zhuǎn)發(fā)就是把函數(shù)參數(shù)"原汁原味"地傳遞給另一個(gè)函數(shù),保持它的所有特性(比如是左值還是右值,是const還是non-const)。

在C++中,這通常通過模板和std::forward實(shí)現(xiàn):

template <typename... Args>
void emplace_back(Args&&... args) {
    // 在容器內(nèi)部直接構(gòu)造對象
    // 完美轉(zhuǎn)發(fā)所有參數(shù)
    new (memory_location) T(std::forward<Args>(args)...);
}

這樣的設(shè)計(jì)讓emplace_back能夠接受任意數(shù)量、任意類型的參數(shù),并且完美地轉(zhuǎn)發(fā)給對象的構(gòu)造函數(shù)。這就是為什么你可以直接這樣寫:

people.emplace_back("張三", 25);  // 直接傳構(gòu)造函數(shù)參數(shù)

而不需要先構(gòu)造一個(gè)對象。

"還有其他 emplace 系列函數(shù)嗎?"

是的!STL容器中有一系列的emplace函數(shù):

  • vector、deque、list: emplace_back()
  • list, forward_list: emplace_front()
  • 所有容器: emplace()(在指定位置構(gòu)造元素)
  • 關(guān)聯(lián)容器(map, set等): emplace_hint()(帶提示的插入)

它們的共同點(diǎn)是:直接在容器內(nèi)部構(gòu)造元素,而不是先構(gòu)造再拷貝/移動。

實(shí)戰(zhàn)建議:什么時(shí)候用 emplace_back?

  • 復(fù)雜對象插入:當(dāng)你要插入的對象構(gòu)造成本高、拷貝代價(jià)大時(shí)
  • 大量數(shù)據(jù)操作:需要插入大量元素時(shí),性能差異會更明顯
  • 直接傳參更方便時(shí):比如插入 pair 到 map
// 不那么優(yōu)雅
std::map<int, std::string> m;
m.insert(std::make_pair(1, "one"));

// 更優(yōu)雅,也更高效
m.emplace(1, "one");
  • 臨時(shí)對象場景:當(dāng)你需要?jiǎng)?chuàng)建臨時(shí)對象并插入容器時(shí)

總結(jié)

emplace_back本質(zhì)上是通過減少不必要的對象創(chuàng)建和拷貝來提升性能。它利用了 C++ 的完美轉(zhuǎn)發(fā)功能,讓你可以直接傳遞構(gòu)造函數(shù)參數(shù),而不需要先創(chuàng)建臨時(shí)對象。

在處理復(fù)雜對象或大量數(shù)據(jù)時(shí),這種優(yōu)化尤為明顯。當(dāng)然,對于簡單類型或已有對象,兩者差異不大。

所以下次當(dāng)你在寫:

myVector.push_back(MyClass(arg1, arg2));

的時(shí)候,不妨試試:

myVector.emplace_back(arg1, arg2);

代碼更簡潔,運(yùn)行更高效,何樂而不為呢?

記住,在編程世界里,這種看似微小的優(yōu)化,累積起來就是質(zhì)的飛躍!

責(zé)任編輯:趙寧寧 來源: 跟著小康學(xué)編程
相關(guān)推薦

2022-03-11 07:59:09

容器代碼元素

2025-02-07 09:58:43

C++11Lvalue對象

2009-10-22 10:18:45

Back-to-BacCCIE

2010-08-10 15:42:31

DB2 back 存檔

2009-12-01 11:31:59

不間斷電源

2009-12-01 11:27:18

不間斷電源

2013-12-19 14:32:31

Android ApiAndroid開發(fā)Android SDK

2021-01-04 20:40:21

微軟Windows 10Windows

2024-07-26 08:35:29

2024-01-22 08:21:46

APPHomemCount

2022-01-09 23:38:42

通信協(xié)議網(wǎng)絡(luò)

2021-02-06 13:11:28

SQL系統(tǒng)數(shù)據(jù)庫

2024-07-26 09:33:22

2013-06-14 14:41:41

Android開發(fā)pushSMS push

2022-09-07 09:22:36

SpringBootWeb

2022-09-13 12:04:53

知乎信息App

2020-10-16 09:09:56

代碼業(yè)務(wù)模型

2011-11-09 14:54:26

2025-06-05 04:22:00

SQL性能索引

2013-07-31 13:03:51

Windows PhoWindows Pho
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號