簡體   English   中英

在構造函數初始化列表上移動shared_ptr

[英]move shared_ptr on constructor initialization list

最近,我看到了一些這樣的代碼示例,其中在構造函數初始化列表(而不是移動構造函數)上使用了std :: move。

class A {
public:
    A(std::shared_ptr<Res> res) : myRes(std::move(res)) {
    // ...
    }

private:
    std::shared_ptr<Res> myRes;
}

我得到的信息是,此構造是出於優化原因進行的。 我個人使用std :: mo盡可能少。 我威脅他們為演員(如斯科特·邁耶斯所說),並且只在調用者代碼中(唯一的例外是move構造函數)。 對我來說,這似乎有些混淆或微優化,但也許我錯了。 沒錯,沒有std :: move,編譯器不會產生更快的代碼?

我考慮了缺少的std::move() ,其中可以移動非平凡的對象,但編譯器無法檢測到這種情況是代碼錯誤。 也就是說,構造函數中的std::move()是強制性的:顯然,構造函數所調用的臨時對象將超出范圍,即可以安全地移出該對象。 另一方面,從參數構造成員變量並不是刪除副本的情況之一。 也就是說,編譯器必須創建一個副本,對於std::shared_ptr<T>來說肯定不是很昂貴,但它也不是免費的。 特別是,更新的參考計數需要同步。 差異是否可以衡量是另一個問題。 運行一個簡單的基准測試(見下文)似乎暗示着性能確實有所提高。 通常我得到的結果是這樣的:

// clang:
copy: 440
move: 206
copy: 414
move: 209
// gcc:
copy: 361
move: 167
copy: 335
move: 170

注意,在這種情況下,您稱為成員的構造函數! 正確的是, std::move(res)只是一種編寫static_cast<std::shared_ptr<RES>&&>(res)方法(它是對static_cast<std::shared_ptr<RES>&&>(res)的替代)。 但是,在對象將超出范圍但以其他方式復制的地方使用它至關重要。 從語義上講,在許多情況下, std::move()的使用無關緊要(僅在語義上與可移動但不可復制的類型有關)。 避免不必要的復制是一項重要的性能改進,並且std::move()在編譯器無法推斷出是否可以這樣做或不允許這樣做的情況下幫助這樣做:特定情況是編譯器可能會執行的操作甚至自己檢測到移動是安全的,但不允許用移動代替副本。 如果在這種情況下編譯器警告缺少std::move() ,那就太好了!

#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <memory>
#include <ostream>
#include <vector>

class timer
{
    typedef std::chrono::high_resolution_clock clock;
    clock::time_point d_start;
public:
    timer(): d_start(clock::now()) {}
    std::ostream& print(std::ostream& out) const {
        using namespace std::chrono;
        return out << duration_cast<microseconds>(clock::now() - this->d_start).count();
    }
};

std::ostream& operator<< (std::ostream& out, timer const& t)
{
    return t.print(out);
}

struct ResCopy
{
    std::shared_ptr<unsigned int> d_sp;
    ResCopy(std::shared_ptr<unsigned int> sp): d_sp(sp) {}
    unsigned int value() const { return *this->d_sp; }
};

struct ResMove
{
    std::shared_ptr<unsigned int> d_sp;
    ResMove(std::shared_ptr<unsigned int> sp): d_sp(std::move(sp)) {}
    unsigned int value() const { return *this->d_sp; }
};

template <typename Res>
void measure(char const* name, std::vector<std::shared_ptr<unsigned int>> const& v)
{
    timer t;
    unsigned long value(0);
    for (int c(0); c != 100; ++c) {
        for (std::size_t i(0), end(v.size()); i != end; ++i) { 
            value += Res(v[i]).value();
        }
    }
    std::cout << name << ": " << t << '\n';
}

int main()
{
    std::vector<std::shared_ptr<unsigned int>> v;
    std::generate_n(std::back_inserter(v), 100,
                    []{ return std::shared_ptr<unsigned int>(new unsigned int(std::rand())); });

    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
    measure<ResCopy>("copy", v);
    measure<ResMove>("move", v);
}

暫無
暫無

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

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