使 std::unique<T> 与 std::unique<const T, CustomDeleterType 兼容>
Make std::unique<T> compatible with std::unique<const T, CustomDeleterType>
在代码中,我为特定对象定义了3个std::unique_ptr指针类型:
typedef std::unique_ptr<MyObject> nonConstPtrDefaultDelete;
typedef std::unique_ptr<MyObject, std::function<void(MyObject *)>>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, std::function<void(const MyObject *)>>
ConstPtrCustomDelete;
我遇到了一个用例,我需要转换nonConstPtrDefaultDelete到ConstPtrCustomDelete和nonConstPtrCustomDelete到ConstPtrCustomDelete。换句话说:
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1(a); // Compiler error Deleter has incompatible type
ConstPtrCustomDelete c2(b); // Compiler error Deleter has incompatible type
主要问题来自于删除函数的类型签名不兼容。可以通过以下方式修改nonConstPtrCustomDelete类型的定义来修复nonConstPtrCustomDelete情况:
typedef std::unique_ptr<MyObject, std::function<void(const MyObject *)>>
nonConstPtrCustomDelete
然而,DefaultDelete最常见的情况仍然产生编译错误,尽管直观上很清楚转换是可能的。是否有一种方法可以解决这个限制,并提示编译器函数可以从一个转换到另一个?
谢谢
如果您确定deleter是合适的,您可以将DefaultDelete转换为您的类型:
nonConstPtrDefaultDelete a;
ConstPtrCustomDelete c1( a.release(), your_deleter );
与const/non const版本相同。但是为什么需要两个版本(一个用于const,一个用于not)还不清楚。
给出的例子,
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1(a); // Compiler error Deleter has incompatible type
ConstPtrCustomDelete c2(b); // Compiler error Deleter has incompatible type
白马王子;有两个问题:
不能从左值表达式构造
unique_ptr
。它是单一所有权,但是左值表达式要求一个副本。对于删除器,功能类型
void(T*)
与功能类型void(T const*)
不兼容
当指针类型为T const*
时需要void(T const*)
delete函数,当指针类型为T*
时也可以很好地工作。所以,撇开惯例不谈,这是最实用的惯例。然而,在c++第一次标准化之前,通过T const*
进行删除被认为是非常不自然的(并且在构造和销毁过程中对象的常量变化也没有得到很好的理解),因此delete p;
对于这样的指针是无效的。
<utility>
头中的std::move
:
ConstPtrCustomDelete c1( move( a ) );
ConstPtrCustomDelete c2( move( b ) );
对于第二个问题,一个解决方案是为每个unique_ptr
配备一个自定义删除器,例如std::default_delete<T const>
的实例。
另一个解决方案是在需要自定义删除器的情况下使用更容易接受的删除器类型,即1处理const
-ness的删除器:
template< class Type >
class Deleter
{
private:
function<void(Type const*)> d_;
public:
using Mutable_type = typename remove_const<Type>::type;
void operator()( Type const* p ) const
{
d_( p );
}
Deleter(): d_( default_delete<Type const>() ) {}
Deleter( default_delete<Mutable_type> const& )
: d_( default_delete<Type const>() )
{}
template< class D >
Deleter( D const& d )
: d_( [d]( Type const* p ) {
d( const_cast<Mutable_type*>( p ) );
} )
{}
};
您的示例代码与move
和这样一个自定义删除器,然后是
typedef std::unique_ptr<MyObject> nonConstPtrDefaultDelete;
typedef std::unique_ptr<MyObject, Deleter<MyObject>>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, Deleter<MyObject const>>
ConstPtrCustomDelete;
nonConstPtrDefaultDelete a;
nonConstPtrCustomDelete b;
ConstPtrCustomDelete c1( move( a ) );
ConstPtrCustomDelete c2( move( b ) );
<子>1在一种罕见的情况下,const_cast
有一个潜在的问题,即当对象最初是const
并且删除函数d
在析构函数之前调用一些非const
成员函数时,形式UB。这可以通过通过模板参数使此转换支持显式选择来解决。例如,客户端代码显式地保证了一个普通的行为良好的函数。 子>
这应该能解决你的问题:
template<class T>
using smarter_default_delete = std::default_delete<const T>;
template<class T, class D=smarter_default_delete<T>>
using my_unique_ptr = std::unique_ptr<T, D>;
typedef my_unique_ptr<MyObject> nonConstPtrDefaultDelete;
基本上,default_delete
不接受T const*
s。
您还可以跳过其他两个类型的限制来强制转换工作。但是上面看起来更简单。
为什么在这里使用std::function
?
你真的需要不同的nonConstPtrCustomDelete
实例有不同的delete共享相同的签名,还是所有的实例使用相同的delete ?
。你曾经这样做过吗?
void foo_deleter(MyObject*);
void bar_deleter(MyObject*);
nonConstPtrCustomDelete ptr1{ foo(), foo_deleter };
nonConstPtrCustomDelete ptr1{ bar(), bar_deleter };
或only this:
nonConstPtrCustomDelete ptr1{ foo(), foo_deleter };
nonConstPtrCustomDelete ptr1{ bar(), foo_deleter };
如果只有后者,那么使用std::function
是毫无意义的,而且效率低下。如果总是使用相同的删除器,则不需要多态类型擦除函数对象。
你应该写一个自定义的删除类型:
struct non_const_deleter {
void operator()(MyObject*) const;
};
则typepedef可以是:
typedef std::unique_ptr<MyObject, non_const_deleter>
nonConstPtrCustomDelete;
也更容易使用,因为这个删除器可以默认构造,所以你不需要显式地提供它:
nonConstPtrCustomDelete ptr1{ foo() };
完全等价于:
nonConstPtrCustomDelete ptr1{ foo(), non_const_deleter{} };
现在您可以添加第二个删除器类型,non_const_deleter
可以转换为:
struct const_deleter {
const_deleter() = default;
const_deleter(const non_const_deleter&) { }
void operator()(const MyObject*) const;
};
或者让一个类型处理两种情况:
struct const_and_non_const_deleter {
void operator()(MyObject*) const;
void operator()(const MyObject*) const;
};
那么这两种类型可以使用相同的删除符:
typedef std::unique_ptr<MyObject, const_and_non_const_deleter>
nonConstPtrCustomDelete;
typedef std::unique_ptr<const MyObject, const_and_non_const_deleter>
constPtrCustomDelete;
和你不会有问题转换nonConstPtr到constPtr
- 为什么 std::unique 不调用 std::sort?
- EASTL矢量<向量<int>>连续的
- 生成"unique"矩阵
- 我对 std::unique(算法)C++有问题
- std::shared_ptr::unique(),复制和线程安全
- 如何在C++03中用自定义谓词调用std::unique
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- C 字符串比较“祝您好运”&gt;“再见”
- C++ std::unique并没有显示我对它的期望
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C++14 unique_ptr并使用已删除的函数'std::unique-ptr' unique_ptr错误
- C++ 如何生成 10,000 个 UNIQUE 随机整数以存储在 BST 中?
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- C 操作员&gt;&gt;与突变器过载
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 是否需要使用 - &gt;运算符在C 中调用成员函数时
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11