簡體   English   中英

我應該std ::在移動構造函數中移動shared_ptr嗎?

[英]Should I std::move a shared_ptr in a move constructor?

考慮:

#include <cstdlib>
#include <memory>
#include <string>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;

class Gizmo
{
public:
    Gizmo() : foo_(shared_ptr<string>(new string("bar"))) {};
    Gizmo(Gizmo&& rhs); // Implemented Below

private:
    shared_ptr<string> foo_;
};

/*
// doesn't use std::move
Gizmo::Gizmo(Gizmo&& rhs)
:   foo_(rhs.foo_)
{
}
*/


// Does use std::move
Gizmo::Gizmo(Gizmo&& rhs)
:   foo_(std::move(rhs.foo_))
{
}

int main()
{
    typedef vector<Gizmo> Gizmos;
    Gizmos gizmos;
    generate_n(back_inserter(gizmos), 10000, []() -> Gizmo
    {
        Gizmo ret;
        return ret;
    });

    random_shuffle(gizmos.begin(), gizmos.end());

}

在上面的代碼中,有兩個版本的Gizmo::Gizmo(Gizmo&&) - 一個使用std::move實際移動 shared_ptr ,另一個只復制shared_ptr

這兩個版本似乎都在表面上工作。 一個區別(我能看到的唯一區別)是在非move版本中, shared_ptr的引用計數暫時增加,但只是暫時增加。

我通常會繼續move shared_ptr ,但只是在我的代碼中清晰且一致。 我在這里錯過了考慮嗎? 出於技術原因,我是否應該優先考慮另一個版本?

這里的主要問題不是由於shared_ptr額外的原子增量和減量而導致的小的性能差異,而是除非您執行移動,否則操作的語義是不一致的。

雖然假設shared_ptr的引用計數只是臨時的,但語言中沒有這樣的保證。 您要移動的源對象可以是臨時對象,但它也可以具有更長的生命周期。 它可能是一個命名變量,已經被轉換為rvalue-reference (比如std::move(var) ),在這種情況下,如果不從shared_ptr 移動 ,你仍然保持與移動源的共享所有權,如果目標shared_ptr具有較小的范圍,然后將不必要地擴展指向對象的生命周期。

我贊成了James McNellis的回答。 我想對他的答案發表評論,但我的評論不符合評論格式。 所以我把它放在這里。

測量移動shared_ptr與復制一個的性能影響的有趣方法是使用vector<shared_ptr<T>>來移動或復制它們的一大堆並計時。 大多數編譯器都可以通過指定語言模式來打開/關閉移動語義(例如-std = c ++ 03或-std = c ++ 11)。

這是我剛剛在-O3測試的代碼:

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

int main()
{
    std::vector<std::shared_ptr<int> > v(10000, std::shared_ptr<int>(new int(3)));
    typedef std::chrono::high_resolution_clock Clock;
    typedef Clock::time_point time_point;
    typedef std::chrono::duration<double, std::micro> us;
    time_point t0 = Clock::now();
    v.erase(v.begin());
    time_point t1 = Clock::now();
    std::cout << us(t1-t0).count() << "\u00B5s\n";
}

使用clang / libc ++和-std = c ++ 03這個打印出來給我:

195.368µs

切換到-std = c ++ 11我得到:

16.422µs

你的旅費可能會改變。

move的使用是可取的:它應該比復制更有效,因為它不需要額外的原子增量和引用計數的減少。

暫無
暫無

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

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