我有一个函数,它返回一个std::pair<objectA*, objectB*>
。该函数的文档表明,我有责任处理这两个元素。现在我只是在做:
{
std::pair<objectA*, objectB*> the_pair;
...
if (condition) {
delete the_pair.first;
delete the_pair.second;
return;
}
...
delete the_pair.first;
delete the_pair.second;
}
当the_pair
超出范围时,我如何使用智能指针自动删除这两个元素?
如果我理解正确,那么调用者有责任删除指针。在这种情况下,您可以创建一个unique_ptr来管理对中的每个元素:
{ // some scope
std::pair<objectA*, objectB*> the_pair = the_function();
std::unique_ptr<objectA> pfirst(the_pair.first);
std::unique_ptr<objectB> psecond(the_pair.second);
} // pointers get deleted
或者,您可以编写自己的范围保护:
struct pointer_pair_guard
{
pointer_pair_guard(std::pair<objectA*, objectB*>& p) : p_(p) {}
~pointer_pair_guard()
{
delete p_.first;
delete p_.second;
}
pointer_pair_guard(const pointer_pair_guard&) = delete;
pointer_pair_guard& operator=(const pointer_pair_guard&) = delete;
private:
std::pair<objectA*, objectB*>& p_;
};
然后
{ // some scope
std::pair<objectA*, objectB*> the_pair = the_function();
pointer_pair_guard gd(the_pair);
} // pointers get deleted
我很想存根函数并使用存根。
std::pair<
std::shared_ptr<objectA>,
std::shared_ptr<objectB>
> nice_foo(...)
{
std::pair<objectA*, objectB*> temp = bad_foo(...);
return std::pair<
std::shared_ptr<objectA>,
std::shared_ptr<objectB>
>(std::shared_ptr<objectA>(temp.first), std::shared_ptr<objectB>(temp.second));
}
在代码中,不要调用bad_foo
,而是调用nice_foo
。返回的对拥有内存,所以您不需要担心删除它。
std::pair<std::unique_ptr<A>,std::unique_ptr<B>>
是显而易见的解决方案。但我们希望它在使用时是干净的。因此:
template<class...Ts, template<class...>class tup, class... Us, size_t...Is>
tup<Ts...> tuple_cast(std::index_sequence<Is...>,tup<Us...>&&u){
return tup<Ts...>{static_cast<Ts>(std::get<Is>(std::move(u)))...};
}
template<class...Ts, template<class...>class tup, class... Us, size_t...Is>
tup<Ts...> tuple_cast(std::index_sequence<Is...>,tup<Us...>const&u){
return tup<Ts...>(static_cast<Ts>(std::get<Is>(u))...);
}
template<class...Ts, template<class...>class tup, class... Us>
tup<Ts...> tuple_cast(tup<Us...>&&u){
static_assert( sizeof...(Ts)==sizeof...(Us), "must map one type to one type" );
return tuple_cast<Ts...>(std::index_sequence_for<Us...>{}, std::move(u));
}
template<class...Ts, template<class...>class Tup, class... Us>
Tup<Ts...> tuple_cast(Tup<Us...>const&u){
static_assert( sizeof...(Ts)==sizeof...(Us), "must map one type to one type" );
return tuple_cast<Ts...>(std::index_sequence_for<Us...>{}, u);
}
现在CCD_ 6是将一对指针变成一对唯一指针的方式。
我们可以做得更好。
template<class A>
struct as_unique{using type=A;};
template<class A>
struct as_unique<A*>{using type=std::unique_ptr<A>;};
template<class A>
using as_unique_t=typename as_unique<A>::type;
template<class...Ts, template<class...>class tup>
tup<as_unique_t<Ts>...> take_ownership(tup<Ts...>&& t){
return tuple_cast<as_unique_t<Ts>...>(std::move(t));
}
如果拼写错误被修复,我们得到:
auto p = take_ownership( func() );
在使用时看起来更干净2这取std::pair
或std::tuple
中的任何指针值T*
,将它们转换为std::unique_ptr<T>
s,生成相应的输出类型,然后使用static_cast
强制转换每个字段,使转换显式。
实例
上面使用了C++14索引序列。它们可以用C++11写十几行左右,所以我并不觉得不好。