模板别名shared_ptr和unique_ptr时是否存在任何问题或限制
Are there any gotchas or limitations when template aliasing shared_ptr and unique_ptr?
为了减少键入以下内容的简单原因:
std::shared_ptr<...>;
std::unique_ptr<...>;
每次我想使用智能指针时,我都会考虑使用模板别名:
template <typename T> using sptr = std::shared_ptr<T>;
template <typename T> using uptr = std::unique_ptr<T>;
所以我可以像这样使用它们:
sptr<...>;
uptr<...>;
假设我在自己的命名空间中保护它们,那么以这种方式使用带有shared/unique_ptr的模板别名是否有任何困难或限制?我会不能用直接模板语法做一些我不能用别名做的事情?出于其他原因,这是个坏主意吗?
这很好,不会对代码产生不可预见的后果。
在您的示例中,std::unique_ptr<T>
和std::shared_ptr<T>
将与uptr<T>
和sptr<T>
相同。你甚至可以用一个静态断言来验证这一点:
static_assert(std::is_same<std::shared_ptr<T>, sptr<T>>::value, "");
使用别名声明被认为是完全相同的类型不仅"相似",而且完全相同。这就是为什么可以继续进行这项工作,而不必担心以后会有任何后果
您的别名声明将来唯一会限制的是将其他参数传递给类型以外的智能指针的能力,例如std::unique_ptr
可以接受deleter。如果你愿意,你可以修改你的using声明,用一个可选的deleter参数来包含一个更完整的定义,尽管我预计大多数人永远不会使用这个功能。
另一方面,需要记住的另一件事是,还有谁会阅读您的代码?std::shared_ptr
是清楚和明显的,但sptr
不太清楚。或者更确切地说,也许不是"不太清楚",但它需要被理解。它为坐下来查看代码的人增加了一个减速带,因为他们需要将uptr
和sptr
内部转换为unique_ptr
和shared_ptr
。
引用标准(7.1.3)
用typedef说明符声明的名称将成为typedef名称。在其声明的范围内,typedef名称在语法上是等效于关键字,并命名与标识符,如第8条所述因此typedef名称就是另一种类型的同义词。typedef名称不会引入新类型类声明(9.1)或枚举声明的方式。
typedef名称也可以通过别名声明引入。这个using关键字后面的标识符变为typedef名称标识符appentains后面的可选属性说明符seq到typedef名称它的语义与由typedef说明符引入。特别是,它没有定义一个新的类型,它不应该出现在类型id中。
答案已经给出,在您的情况下,答案是一样的,但模板别名有时可能真的会引入新名称,这里是一个示例
#include <type_traits>
template <typename T> class A {};
template <typename T> using B = A<T>;
template < template <typename T> class S> class C {};
static_assert( std::is_same< A<int>, B<int> >::value, "same :)"); // they are the same
static_assert( std::is_same< C<A>, C<B> >::value, "not the same :("); // error, not the same
这里,即使A
和B
相同,C<A>
和C<B>
也不同。
对于std::shared_ptr<T
,通过为其提供不同的名称永远不会有任何问题
template <typename T>
using sptr = std::shared_ptr<T>;
因为这些名称在定义上是等价的。
唯一指针是另一回事,因为您忽略了模板参数。因此,您只能获得uptr
的默认模板参数,这限制了uptr
的使用情况而不是unique_ptr
。
考虑一下这个小代码:
std::unique_ptr<FILE, void (*)(FILE*)> file(fopen("myfile.txt", "r"), [](FILE* f)
{
fclose(f);
});
// use file here to perform input operations
// automatic call to fclose at the end of scope (or any scope exit)
这里,删除程序的默认类型(即std::default_delete<T>
)被替换,以正确关闭FILE*
。这一点很重要,因为FILE*
不是new
。这也适用于任何C接口,在那里你需要free
而不是delete
,因为默认的deleterdelete
s,这与free
ing不同。
您的uptr<T>
无法支持,因为它是template <typename T> using uptr<T> = ...
而不是template <typename T, typename D = std::default_deleter<T>> using uptr<T, D> = ...
。
如果您从未对拥有不同的deleter感兴趣,那么将unique_ptr
重命名为uptr
也没有害处,因为类型完全相同。
不要这样做。是的,你当然可以这样做,但你应该这样做吗?IHMO,它会降低代码的可读性,因为每个人都知道std::unique_ptr<>
是什么,但没有人知道uptr<>
是什么,除了谁写了那个奇怪的代码。。。
维护良好的代码易于阅读,使用类型和值的名称来表达它们的目的和意图,因此只需要最少的注释(避免注释,因为它们很难维护)。有了你较短的uptr<>
,你就要离开这条智慧之路了。。。
当然,您可以使用更具描述性的名称,如unique_pointer
(在注释中建议),并使用typedefs通过std::unique_ptr
或boost::unique_ptr
(如果没有std::unique_ptr
,我会认为您也没有移动语义,因此unique_pointer
的全部意义就没了)来实现它。但这对减少键入没有帮助。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 奇怪的(对我来说)返回声明 - 在谷歌上找不到任何关于它的信息
- 如何在不产生任何垃圾的情况下获得C中的像素
- 为什么我不能在 C++ 中的特定函数重载中调用同一函数的任何其他重载?
- CLANG 编译器 说:变量"PTR"可能未初始化
- C++映射有2个键,这样任何1个键都可以用来获取值
- Visual Studio(或任何其他工具)能否将地址解释为调用堆栈(boost上下文)的开头
- RtlCaptureStackBackTrace未捕获任何帧
- 在以唯一ptr为值的C++映射中,动态内存何时会被销毁
- 链表c++插入,所有情况都已检查,但没有任何工作
- C++模板函数,用于比较任何无符号整数和有符号整数
- Arduino millis() - millis() 怎么能等于 0 以外的任何东西?
- 尝试摆脱任何堆内存分配
- 是否有任何C++功能可以对地图进行排序?
- 将 ptr 传递给 ptr 到 A 作为参数传递给 A 的函数是不好的做法吗?
- 打印时有二叉树问题.用户输入不打印任何内容
- 共享指针和具有自定义删除程序的唯一指针之间的语法差异背后的任何原因
- 在C++行尾写一个分号或多个分号是否会改变任何内容
- 为什么我不能在不进行任何转换的情况下将浮点数放入任何类型的 ptr 中?
- 有没有办法在数组上遍历shared_或任何"smart" ptr?