是否支持从unique_ptr到原始指针的隐式转换
Is implicit conversion from unique_ptr to raw pointer supported?
我在读Effective c++第三版。在第70页,作者说:
像几乎所有智能指针类一样,
tr1::shared_ptr
和auto_ptr
也重载指针解引用操作符(operator->
和operator*
),这允许隐式转换为底层原始指针(…)
然后他展示了一个shared_ptr
(当时是tr1
的一部分)的例子,基于一个名为Investment
的类进行隐式转换:
shared_ptr<Investment> pi1();
bool taxable1 = !(pi1->isTaxFree());
^implicit conversion
shared_ptr<Investment> pi2();
bool taxable2 = !((*pi2).isTaxFree());
^implicit conversion
从那以后,我用unique_ptr
写了几个测试用例,它们都很好。
我还发现unique_ptr
支持数组,shared_ptr
也将(见注释)。然而,在我的测试中,隐式转换似乎对数组周围的智能指针不起作用。
示例:我希望这是有效的…
unique_ptr<int[]> test(new int[1]);
(*test)[0] = 5;
但它不是,根据我的编译器(Visual c++ 2015 Update 3)。
然后,从一个小研究中,我发现一些证据表明隐式转换根本不支持…例如:https://herbsutter.com/2012/06/21/reader-qa-why-dont-modern-smart-pointers-implicitly-convert-to.
在这一点上,我很怀疑。是否支持(由标准),还是不支持?
注意:这本书在这个主题上可能有点过时,因为作者还在第65页上说"对于动态分配的数组,没有像auto_ptr
或tr1::shared_ptr
这样的东西,甚至在TR1中也没有"。
事情是这样的。没有到底层指针的隐式转换,您必须调用特定的get
成员函数(它是标准库中的主题,考虑std::string::c_str
)。
但这是一件好事!隐式转换指针可能会破坏unique_ptr
的保证。考虑以下内容:
std::unique_ptr<int> p1(new int);
std::unique_ptr<int> p2(p1);
在上面的代码中,编译器可以尝试将p1
的指针传递给p2
!(它不会,因为这个调用将是模棱两可的,但假设它不是)。他们都将呼叫delete
!但是我们仍然希望使用智能指针,就好像它是一个原始指针一样。因此,所有操作符都是重载的。
现在让我们考虑你的代码:
(*test)[0] = 5;
它调用unique_ptr::operator*
,产生一个int&
1。然后尝试使用下标操作符。那是你的错误。如果你有一个
std::unique_ptr<int[]>
,那么就使用句柄提供的operator[]
重载:
test[0] = 5;
1正如David Scarlett指出的那样,它甚至不应该编译。数组版本不应该有这个操作符
正如StoryTeller所指出的那样,隐式转换会破坏节目,但我想建议从另一种方式考虑这个问题:
像unique_ptr
和shared_ptr
这样的智能指针试图隐藏底层的原始指针,因为它们试图维护它的某种所有权语义。如果您要自由地获取该指针并传递它,则很容易违反这些语义。他们仍然提供了一种访问它的方法(get
),因为即使他们想要,他们也不能完全阻止你(毕竟你可以跟随智能指针并获得指针的地址)。但他们仍然想设置一个屏障,以确保你不会意外访问它。
但并非全输了!您仍然可以通过定义一种语义非常弱的新型智能指针来获得语法上的便利,这样就可以安全地从大多数其他智能指针隐式构造它。考虑:
// ipiwdostbtetci_ptr stands for :
// I promise I wont delete or store this beyond the expression that created it ptr
template<class T>
struct ipiwdostbtetci_ptr {
T * _ptr;
T & operator*() {return *_ptr;}
T * operator->(){return _ptr;}
ipiwdostbtetci_ptr(T * raw): _ptr{raw} {}
ipiwdostbtetci_ptr(const std::unique_ptr<T> & unq): _ptr{unq.get()} {}
ipiwdostbtetci_ptr(const std::shared_ptr<T> & shr): _ptr{shr.get()} {}
};
那么,这个具有讽刺意味的智能指针的意义是什么呢?它只是一种指针,它被口头赋予了一个契约,用户永远不会保留它或它的副本,超过创建它的表达式,用户也永远不会试图删除它。有了用户遵循的这些约束(无需编译器检查),隐式转换许多智能指针和任何原始指针都是完全安全的。
现在您可以实现期望ipiwdostbtetci_ptr
的函数(假设它们会遵守语义),并方便地调用它们:
void f(ipiwdostbtetci_ptr<MyClass>);
...
std::unique_ptr<MyClass> p = ...
f(p);
- 正在将指针转换为范围
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- C++:Lambda 函数指针转换的用例是什么?
- 如何将 int 指针转换为浮点指针
- 为什么在将 void 指针转换为整数指针时出现分段错误
- 将(N 个字节)无符号字符指针转换为浮点数和双 C++
- 我们可以在不知道其真实类型的情况下将基类指针转换为派生类指针吗?
- C++中数组大小未知的指针转换
- Antlr cpp 运行时 任何错误的指针转换?
- std::flush可以用于将对象指针转换为其封闭数组指针吗
- C 指针转换会导致内存访问冲突
- 模板类实例化中的指针转换无效
- 函数调用歧义(用户定义的转换和 Derived2Base 指针转换)
- 如何将 void(*)() 类型的指针转换为 void*
- 数组到指针转换期间的临时具体化
- 直接为浮点变量分配十六进制整数与通过指针转换分配之间的区别
- 将基类指针转换为派生的类指针
- 应对 std::字符串中的 std::<char>指针转换后的向量
- 在编译时将函数指针转换为 std::uintptr_t
- 将基类指针转换为未知派生类指针