簡體   English   中英

如何在`push_*()` 和`emplace_*()` 函數之間進行選擇?

[英]How to choose between `push_*()` and `emplace_*()` functions?

我了解兩個函數變體之間的區別。

我的問題是:我是否應該通常使用舊的push_*()版本並且只在我的分析器告訴我這將有利於性能(即不要過早優化)時才切換到emplace_*() ) ? 或者我應該切換到使用emplace_*()作為默認值(也許不要不必要地悲觀代碼 - 類似於for循環中的i++ vs ++i )?

在現實的非人為的用例中,是否有任何變體比另一個更通用(即對插入的類型施加更少的限制)?

在編寫代碼時,我不會擔心性能。 當您已經擁有可以分析的代碼時,性能是稍后使用的。

我寧願擔心代碼的表現力。 粗略地說, push_back用於當您有一個元素並希望在容器內放置一個副本時。 emplace_back是將元素構造到位。

考慮什么具有較低的“wtf-count”:

struct foo {int x;int y;};

void foo_add(const foo& f,std::vector<foo>& v) {
    v.emplace_back(f);   // wtf ?!? we already have a foo
    v.push_back(f);      // ... simply make a copy (or move)
}

void foo_add(int x, int y, std::vector<foo>& v) {
    auto z = foo{x,y};      // wtf ?!? 
    f.push_back(z);         // why create a temporary?
    f.emplace_back(x,y);    // ... simply construct it in place
} 

emplace函數是委托構造函數。

假設你有一個 T 的容器。

如果你已經有一個 T,也許它是 const,也許它是一個右值,也許這些都不是;
然后你使用push_xxx()
您的對象將被復制/移動到容器中。

如果您想構造一個 T,那么您可以使用emplace_xxx() ,其參數與您將發送的構造函數相同
一個對象將直接在容器中構造。

Emplace 函數比 push 函數更通用。 在任何情況下,它們的效率都不會降低,相反 - 它們可以更有效率,因為當您需要從參數構造容器元素時,它們允許優化容器元素的一個復制/移動操作。 當將元素放入容器時,無論如何都涉及復制/移動,因此 emplace 和 push 操作是等效的。

如果您確實想在將元素復制/移動到容器之前強制構造,則推送可能更可取。 例如,如果您的元素類型在其構造函數中有一些您希望在修改容器之前執行的特殊邏輯。 不過,這種情況非常罕見。

如果您以天真的方式從push_back切換到emplace_back ,您將完全沒有優勢。 考慮以下代碼:

#include <iostream>
#include <string>
#include <vector>

struct President
{
    std::string name;
    std::string country;
    int year;

    President(std::string p_name, std::string p_country, int p_year) :
            name(std::move(p_name)), country(std::move(p_country)), year(p_year)
    {
        std::cout << "I am being constructed.\n";
    }
    President(President&& other) :
            name(std::move(other.name)), country(std::move(other.country)),
            year(other.year)
    {
        std::cout << "I am being moved.\n";
    }
    President& operator=(const President& other) = default;
};

int main()
{
    std::vector<President> elections;
    std::cout << "emplace_back:\n";
    elections.emplace_back("Nelson Mandela", "South Africa", 1994);

    std::vector<President> reElections;
    std::cout << "\npush_back:\n";
    reElections.push_back(
            President("Franklin Delano Roosevelt", "the USA", 1936));

    std::cout << "\nContents:\n";

    for (President const& president : elections)
    {
        std::cout << president.name << " was elected president of "
                            << president.country << " in " << president.year << ".\n";
    }

    for (President const& president : reElections)
    {
        std::cout << president.name << " was re-elected president of "
                            << president.country << " in " << president.year << ".\n";
    }
}

如果你用emplace_back替換push_back你仍然有一個構造然后一個移動。 只有當您傳遞構造所需的參數而不是構造的實例本身時(請參閱對emplace_back的調用),您才節省了精力。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM