2016-04-05 51 views
3

我想要std::shared_ptr<std::tuple<MyClass, std::mutex>>如何將Std :: mutex與其他類放在std :: tuple中?

std::mutex既不可複製也不可移動。如何初始化它?

+4

你可以使用一對嗎? Pair有一個構造函數,它將參數分別轉發給每個類型。另一個常見的解決方案是使用指向互斥體的唯一指針。 –

+1

我不確定,但我不認爲你應該有問題'std :: make_shared >()'如果'MyClass'是默認可構造的。 – vu1p3n0x

+0

@ vu1p3n0x,它不是默認的可構造的。 – Velkan

回答

1

兩個參數的簡單解決方案是std::pairstd::piecewise_construct

std::tuple缺少那個。我認爲這是一個缺陷。

如果我們想要tuple(說超過2個參數),我們可以用一些可怕的代碼來做到這一點,對於「可以做到」的有限值。

template<class T> 
struct placement_shared_helper { 
    std::aligned_storage_t<sizeof(T),alignof(T)> data; 
    T* get() { return reinterpret_cast<T*>(&data); } 
    template<class F> 
    void construct(F&& f) { 
    std::forward<F>(f)((void*)&data); 
    } 
    // dangerous if construct throws: 
    ~placement_shared_helper(){ get()->~T(); } 
}; 

template<class T, class F> 
std::shared_ptr<T> make_placement_shared(F&& f) { 
    auto r1 = std::make_shared<placement_shared_helper<T>>(); 
    r1->construct(std::forward<F>(f)); 
    return {r1->get(), r1}; // aliasing constructor 
} 

這需要你在一個函數對象,通過足夠的大小和排列的void*時,將構建你的類型所指向的存儲通過。

您可以改進placement_shared_helper的例外安全性,但它是工作而我很懶。考慮從構造和std::terminate中捕獲任何異常。

對於下一部分,我們作弊。這違反了標準,因爲我們採用未初始化的內存並將其解釋爲一個元組,以獲取元組存儲其偏移量的偏移量。糟糕的程序員。

template<class Dest, std::size_t...Is, class...Args> 
void placement_construct(std::index_sequence<Is...>, Dest* here, std::tuple<Args...> args) { 
    new((void*)here) Dest(std::get<Is>(args)...); 
} 
template<class Dest, class...Args> 
void placement_construct(Dest* here, std::tuple<Args...> args) { 
    return placement_construct(std::index_sequence_for<Args...>{}, here, std::move(args)); 
} 

template<class Dest, std::size_t...Is, class...Tuples> 
void placement_construct_tuple(std::index_sequence<Is...>, void* here, Tuples... tuples) { 
    using discard=int[]; 
    (void)discard{0,(void(
     placement_construct(&std::get<Is>(*(Dest*)here), std::move(tuples)) 
),0)...}; 
} 

template<class Dest, class...Tuples> 
void placement_construct_tuple(void* here, Tuples... tuples) { 
    placement_construct_tuple<Dest>(std::index_sequence_for<Tuples...>{}, here, std::move(tuples)...); 
} 

這假設一個元組只是一堆特定位置的構造對象。我們採用我們的元組形式的內存塊並依次構建其每個元素。如果發生異常,會發生不好的事情;你可能想嘗試catch終止。

make_placement_shared需要一個函數,它需要一個void*並構造您的對象。

placement_construct_tuple接收一組元組,並使用它們在元組中依次構造對象。

auto r = make_placement_shared<std::tuple<MyClass, std::mutex>>(
    [&](void* here) { 
    placement_construct_tuple<std::tuple<MyClass, std::mutex>>(here, 
     std::forward_as_tuple(args_to_construct_MyClass_go_here), 
     std::make_tuple() // no args for mutex 
    ); 
    } 
); 

並禁止輸入錯誤和未定義的行爲,完成。

+0

如果你的生活依賴它,你會使用這段代碼嗎? –

+0

@MaximEgorushkin不,我不會將未編譯的模板元編程代碼安裝到心率監視器中,然後將它安裝在我的胸部?那會很愚蠢。我也可能做一個'std :: tuple <可選,std :: mutex>'並且爲訂婚的布爾而吃字節,而不是嘗試上面的。在中期內,我懷疑一個用於元組的piecewise_convert'ctor可能會出現並消除上面的黑客攻擊。 – Yakk

相關問題