我想std::shared_ptr<std::tuple<MyClass, std::mutex>>
。
std::mutex
既不可复制也不可移动。如何初始化?
答案 0 :(得分:1)
两个参数的简单解决方案是std::pair
和std::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)... );
}
这假定元组只是特定位置的一堆构造对象。我们采用元组形状的内存块并依次构造其每个元素。如果抛出异常就会发生坏事;你可能想尝试捕捉终止。
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
);
}
);
并禁止打字错误和未定义的行为,已完成。